题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入输出格式

输入格式:

输入初始状态,一行九个数字,空格用0表示

输出格式:

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例

输入样例#1:

283104765
输出样例#1:

4


普通搜索7000ms
#include <cstdio>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
#define reg register
#define ll long long
ll St, Ed;
map<ll, int> vis;
struct date {
ll hsh;
int stp;
};
const int dx[] = {, , -, , }, dy[] = {, , , , -};
int main()
{
scanf("%lld", &St);
Ed = ;
queue <date> q;
q.push((date){St, });
while(!q.empty())
{
ll hsh = q.front().hsh;
int tp = q.front().stp;
q.pop();
if (hsh == Ed) {
printf("%d\n", tp);
return ;
}
int a[][];
int tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
int x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis[nhsh]) vis[nhsh] = , q.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
}
return ;
}

双向广搜242ms

#include <cstdio>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
#define reg register
#define ll long long
ll St, Ed;
map<ll, int> vis1, vis2;
struct date {
ll hsh;
int stp;
};
const int dx[] = {, , -, , }, dy[] = {, , , , -};
int main()
{
scanf("%lld", &St);
Ed = ;
queue <date> q1, q2;
q1.push((date){St, });
q2.push((date){Ed, });
vis1[St] = , vis2[Ed] = ;
if (St == Ed) return puts(""), ;
while(!q1.empty() and !q2.empty())
{
ll hsh = q1.front().hsh;
int tp = q1.front().stp;
q1.pop();
if (vis2[hsh]) {
printf("%d\n", tp + vis2[hsh]);
return ;
}
int a[][];
int tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
int x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis1[nhsh]) vis1[nhsh] = tp + , q1.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
hsh = q2.front().hsh;
tp = q2.front().stp;
q2.pop();
if (vis1[hsh]) {
printf("%d\n", tp + vis1[hsh]);
return ;
}
tmp = hsh;
for (reg int i = ; i >= ; i --)
for (reg int j = ; j >= ; j --)
a[i][j] = tmp % , tmp /= ;
x = , y = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
if (!a[i][j]) {x = i, y = j;break;}
for (reg int i = ; i <= ; i ++)
{
int tx = x + dx[i], ty = y + dy[i];
if (tx <= or tx > or ty <= or ty > ) continue;
swap(a[x][y], a[tx][ty]);
int nhsh = ;
for (reg int i = ; i <= ; i ++)
for (reg int j = ; j <= ; j ++)
nhsh = nhsh * + a[i][j];
if (!vis2[nhsh]) vis2[nhsh] = tp + , q2.push((date){nhsh, tp + });
swap(a[x][y], a[tx][ty]);
}
}
return ;
}

[Luogu1379]八数码难题的更多相关文章

  1. 双向广搜+hash+康托展开 codevs 1225 八数码难题

    codevs 1225 八数码难题  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description Yours和zero在研究A*启 ...

  2. Codevs 1225 八数码难题

    1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的 ...

  3. [luogu]P1379 八数码难题[广度优先搜索]

    八数码难题 ——!x^n+y^n=z^n 我在此只说明此题的一种用BFS的方法,因为本人也是初学,勉勉强强写了一个单向的BFS,据说最快的是IDA*(然而蒟蒻我不会…) 各位如果想用IDA*的可以看看 ...

  4. 洛谷P1379八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...

  5. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  6. 【洛谷P1379】八数码难题(广搜、A*)

    八数码难题 题目描述 一.广搜: 首先要考虑用什么存每一个状态 显然每个状态都用一个矩阵存是很麻烦的. 我们可以考虑将一个3*3的矩阵用一个字符串或long long 存. 每次扩展时再转化为矩阵. ...

  7. 习题:八数码难题(双向BFS)

    八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...

  8. 「LuoguP1379」 八数码难题(迭代加深

    [P1379]八数码难题 - 洛谷 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种 ...

  9. 洛谷——P1379 八数码难题

    P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...

随机推荐

  1. TestNG(一) TestNG实战在idea中创建module

    1.在ider里创建一个Module 2.直接点击下一步 3.输入Groupld h和Artifactid名称,点击下一步 4.点击Finish 创建完成

  2. Day 1总结

  3. Linux配置部署_新手向(四)——Redis安装与配置

    前言 配置完mysql之后,我们来紧接着安装redis,毕竟这些不用太多的思考,就是命令执行,配置文件,连接测试. 安装 首先,我们要看安装哪个版本,可以在Redis官网看看我们安装哪个版本. 在之前 ...

  4. windows下安装spark

    1.安装jdk 2.安装scala 3.下载spark spark下载地址 3.1安装spark 将下载的文件解压到一个目录,注意目录不能有空格,比如说不能解压到C:\Program Files 作者 ...

  5. 词表征 2:word2vec、CBoW、Skip-Gram、Negative Sampling、Hierarchical Softmax

    原文地址:https://www.jianshu.com/p/5a896955abf0 2)基于迭代的方法直接学 相较于基于SVD的方法直接捕获所有共现值的做法,基于迭代的方法一次只捕获一个窗口内的词 ...

  6. 前端基于VUE的v-charts的曲线显示

    目录 前端基于VUE的v-charts的曲线显示 1. 应用背景 2. 分析数据生产者生成 3. 取出数据消费者 4. 前端显示 4.1 安装V-charts插件 4.2 引入veline曲线插件 4 ...

  7. javascript:history.go(-1)的使用

    1.问题描述 在微信项目开发中,比如常用联系人的增删改查操作中,比如跳入常用联系人管理页面,选中一个联系人修改它,就会跳入修改页面,修改完成后跳转到常用联系人管理页面,此时如果修改成功跳转采用的是页面 ...

  8. windows核心编程 第8章201页旋转锁的代码在新版Visual Studio运行问题

    // 全局变量,用于指示共享的资源是否在使用 BOOL g_fResourceInUse = FALSE; void Func1() { //等待访问资源 while(InterlockedExcha ...

  9. Linux 文件或文件夹重命名命令mv

    使用命令mv既可以重命名,又可以移动文件或文件夹.例如: 1.将目录A重命名为B mv A B 2.将/a目录移动到/b下,并重命名为c mv /a /b/c 3.将一个名为abc的文件重命名为123 ...

  10. 高效解决「SQLite」数据库并发访问安全问题,只这一篇就够了

    Concurrent database access 本文译自:https://dmytrodanylyk.com/articles/concurrent-database/ 对于 Android D ...