题目:八数码

网址:http://poj.org/problem?id=1077

在一个3×3的网格中,1~8这8个数字和一个“X”恰好不重不漏地分布在这3×3的网格中。

例如:

1 2 3
X 4 6
7 5 8

在游戏过程中,可以把“X”与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 X

例如,示例中图形就可以通过让“X”先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3   1 2 3   1 2 3   1 2 3
X 4 6 4 X 6 4 5 6 4 5 6
7 5 8 7 5 8 7 X 8 7 8 X

把“X”与上下左右方向数字交换的行动记录为“u”、“d”、“l”、“r”。

现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。

输入格式

输入占一行,将3×3的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3

x 4 6

7 5 8

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。如果答案不唯一,输出任意一种合法方案即可。

如果不存在解决方案,则输出”unsolvable”。

输入样例:
2  3  4  1  5  x  7  6  8
输出样例:
ullddrurdllurdruldr

很经典的一道广搜题目(A*)。核心就是如何保存状态。

  • 方法一:使用map来记录操作以及set判重。
  • 方法二:康托展开(早晚更新的)。
  • 方法三:hash表判重,码量较大。

STL代码如下:

#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define pii pair <int, int> using namespace std; const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1}; int st, ed = 123456780;
set <int> vis;
map <int, int> d, f;
void decode(int state, int *p)
{
for(int i = 0; i < 9; ++ i)
{
p[8 - i] = state % 10;
state /= 10;
}
return;
}
int encode(int *p)
{
int t = 0;
for(int i = 0; i < 9; ++ i)
{
t = (t << 3) + (t << 1);
t += p[i];
}
return t;
}
int gh(int *p)
{
int cost = 0;
for(int i = 0; i < 9; ++ i)
cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3); return cost;
}
void print(int state)
{
if(state == st) return;
int pre_state = f[state];
print(pre_state);
int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
decode(state, p1), decode(pre_state, p2);
for(i = 0; i < 9; ++ i)
{
if(p1[i] == 0)
{
t1 = i;
break;
}
}
for(i = 0; i < 9; ++ i)
{
if(p2[i] == 0)
{
t2 = i;
break;
}
}
if(t1 < t2)
{
if(t1 - t2 == -1) putchar('l');
else putchar('u');
}
else
{
if(t2 - t1 == -1) putchar('r');
else putchar('d');
}
return;
}
bool valid(int x, int y)
{
if(x < 0 || x > 2 || y < 0 || y > 2) return false;
return true;
}
bool hash_table_judge(int state)
{
if(vis.count(state)) return false;
return true;
}
void hash_table_insert(int next_state, int state)
{
d[next_state] = d[state] + 1;
vis.insert(next_state);
f[next_state] = state;
return;
}
int bfs()
{
if(st == ed) return 0;
d.clear(), vis.clear(), f.clear();
queue <int> Q;
while(!Q.empty()) Q.pop();
int state, next_state, now, next, p[9], x, y;
memset(p, -1, sizeof(p)); hash_table_insert(st, 0);
d[st] = 0;
Q.push(st); while(!Q.empty())
{
state = Q.front();
Q.pop();
decode(state, p);
for(int i = 0; i < 9; ++ i)
{
if(p[i] == 0)
{
now = i;
x = i / 3, y = i % 3;
break;
}
}
for(int i = 0; i < 4; ++ i)
{
if(!valid(x + dx[i], y + dy[i])) continue;
next = (x + dx[i]) * 3 + (y + dy[i]);
swap(p[now], p[next]);
next_state = encode(p);
swap(p[now], p[next]);
if(!hash_table_judge(next_state)) continue;
hash_table_insert(next_state, state);
if(next_state == ed)
{
printf("%d\n", d[state]);
print(state);
return 1;
}
Q.push(next_state);
}
}
return -1;
}
int main()
{
string line;
getline(cin, line);
for(int i = 0; i < line.size(); ++ i)
{
if(line[i] == 'x')
{
line[i] = '0';
break;
}
}
stringstream ss(line);
int tmp;
st = 0;
for(int i = 0; i < 9; ++ i)
{
ss >> tmp;
st = (st << 3) + (st << 1);
st += tmp;
}
if(bfs() == -1) puts("unsolvable");
return 0;
}

hash表代码如下:

#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#define pii pair <int, int>
using namespace std;
const int maxn = 377777 + 5, mod = 377777;
const int dx[4] = {-1, 1, 0, 0};
const int dy[4] = {0, 0, -1, 1}; int st, ed = 123456780, head[maxn] = {}, next[maxn] = {}, table[maxn] = {}, tot = 0;
map <int, int> d, f;
void decode(int state, int *p)
{
for(int i = 0; i < 9; ++ i)
{
p[8 - i] = state % 10;
state /= 10;
}
return;
}
int encode(int *p)
{
int t = 0;
for(int i = 0; i < 9; ++ i)
{
t = (t << 3) + (t << 1);
t += p[i];
}
return t;
}
int hash_table_search(int state)
{
int val = state % mod;
for(int i = head[val]; i; i = next[i])
if(table[i] == state) return i;
return -1;
}
int gh(int *p)
{
int cost = 0;
for(int i = 0; i < 9; ++ i)
cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3); return cost;
}
void print(int state)
{
if(state == st) return;
int pre_state = f[state];
print(pre_state);
int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
decode(state, p1), decode(pre_state, p2);
for(i = 0; i < 9; ++ i)
{
if(p1[i] == 0)
{
t1 = i;
break;
}
}
for(i = 0; i < 9; ++ i)
{
if(p2[i] == 0)
{
t2 = i;
break;
}
}
if(t1 < t2)
{
if(t1 - t2 == -1) putchar('l');
else putchar('u');
}
else
{
if(t2 - t1 == -1) putchar('r');
else putchar('d');
}
return;
}
bool valid(int x, int y)
{
if(x < 0 || x > 2 || y < 0 || y > 2) return false;
return true;
}
bool hash_table_judge(int state)
{
int val = state % mod;
for(int i = head[val]; i; i = next[i])
if(table[i] == state) return false; return true;
}
void hash_table_insert(int next_state, int state)
{
int val = next_state % mod;
table[++ tot] = next_state;
next[tot] = head[val];
head[val] = tot;
f[next_state] = state;
d[next_state] = d[state] + 1;
return;
}
int bfs()
{
if(st == ed) return 0;
d.clear(), f.clear();
queue <int> Q;
while(!Q.empty()) Q.pop();
int state, next_state, now, next, p[9], x, y;
memset(p, -1, sizeof(p)); hash_table_insert(st, 0);
d[st] = 0;
Q.push(st); while(!Q.empty())
{
state = Q.front();
Q.pop();
decode(state, p);
for(int i = 0; i < 9; ++ i)
{
if(p[i] == 0)
{
now = i;
x = i / 3, y = i % 3;
break;
}
}
for(int i = 0; i < 4; ++ i)
{
if(!valid(x + dx[i], y + dy[i])) continue;
next = (x + dx[i]) * 3 + (y + dy[i]);
swap(p[now], p[next]);
next_state = encode(p);
swap(p[now], p[next]);
if(!hash_table_judge(next_state)) continue;
hash_table_insert(next_state, state);
if(next_state == ed)
{
print(state);
return d[state];
}
Q.push(next_state);
}
}
return -1;
}
int main()
{
string line;
getline(cin, line);
for(int i = 0; i < line.size(); ++ i)
{
if(line[i] == 'x')
{
line[i] = '0';
break;
}
}
stringstream ss(line);
int tmp;
st = 0;
for(int i = 0; i < 9; ++ i)
{
ss >> tmp;
st = (st << 3) + (st << 1);
st += tmp;
}
if(bfs() == -1) puts("unsolvable");
return 0;
}

POJ1077 八数码问题的更多相关文章

  1. POJ1077 八数码 BFS

    BFS 几天的超时... A*算法不会,哪天再看去了. /* 倒搜超时, 改成顺序搜超时 然后把记录路径改成只记录当前点的操作,把上次的位置记录下AC..不完整的人生啊 */ #include < ...

  2. ACM/ICPC 之 BFS-广搜进阶-八数码(经典)(POJ1077+HDU1043)

    八数码问题也称为九宫问题.(本想查查历史,结果发现居然没有词条= =,所谓的历史也就不了了之了) 在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同.棋盘上还有一个 ...

  3. 由八数码问题引入。对BFS有更深考虑

    12号到今天共研究八数码问题poj1077,首先用的是普通BFS,遇到很多问题,开始用一个二级指针作为结构成员,知道了二级指针与二维数值名的不同!http://write.blog.csdn.net/ ...

  4. A*算法 -- 八数码问题和传教士过河问题的代码实现

    前段时间人工智能的课介绍到A*算法,于是便去了解了一下,然后试着用这个算法去解决经典的八数码问题,一开始写用了挺久时间的,后来试着把算法的框架抽离出来,编写成一个通用的算法模板,这样子如果以后需要用到 ...

  5. 八数码问题:C++广度搜索实现

    毕竟新手上路23333,有谬误还请指正. 课程设计遇到八数码问题(这也是一坨),也查过一些资料并不喜欢用类函数写感觉这样规模小些的问题没有必要,一开始用深度搜索却发现深搜会陷入无底洞,如果设定了深度限 ...

  6. BFS(八数码) POJ 1077 || HDOJ 1043 Eight

    题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...

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

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

  8. UVALive 6665 Dragon’s Cruller --BFS,类八数码问题

    题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...

  9. P1379 八数码问题

    aoapc上的八数码问题,在luogu上也有类似的题,p1379,经典题目,lrj给出了一个算法,同时给出了三种判重的方法.本来想用std::queue改写一下,但是出了各种问题,只好抄代码ac掉这道 ...

随机推荐

  1. /usr/lib/jvm/java-1.8.0-openjdk/release 没有这个文件或目录

    在Java1.8以上,安装以后再安装目录是自动生成一个release文件,用于记录Java和系统信息.但是在centos中,如果你的Java是在安装系统时选择自动安装的,那么在标题那个目录下,也就是j ...

  2. 【PHP】函数

    一.      数学中的函数: a)    sin().cos().tan().log() 这些都是数学函数,但是都已经忘了啥意思了!没关系,在php当中的函数和这些函数的概念还是有一定的区别的 二. ...

  3. 课程登记窗口java

    设计窗口,实现课程的登记,并且将相应的数据写入文件之中.保证的是课程名称不可以重复,对于任课老师必须是在已经设定好的五位老师之中.并且上课地点也是在预先设定的范围内.窗口可以持续进行保存,数据将在判断 ...

  4. 学习《深入应用c++11》1

    C++11 让程序更简洁.更优雅 可调用对象 是一个函数指针 是一个具有operator()成员函数的类对象(仿函数) 是一个可被装换为函数指针的类对象 是一个类的成员(函数)指针 void func ...

  5. 虚拟机安装windows sever2008

    1.打开并进行新建虚拟机 2.默认选择“典型” 3.选择“安装程序盘映像文件”,并‘浏览’选择本地的文件 4. 5.后面的默认选择即可,安装路径可自己修改 6.这一步的磁盘大小可自己修改的,这里先预设 ...

  6. Python财经数据接口包TuShare的使用

    安装TuShare 方式1:pip install tushare 方式2:访问https://pypi.python.org/pypi/tushare/下载安装 方式3:将源代码下载到本地pytho ...

  7. Pytest系列(21)- allure的特性,@allure.description()、@allure.title()的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 前面介绍了两种allure的 ...

  8. 一篇文章快速搞懂Redis的慢查询分析

    什么是慢查询? 慢查询,顾名思义就是比较慢的查询,但是究竟是哪里慢呢?首先,我们了解一下Redis命令执行的整个过程: 发送命令 命令排队 命令执行 返回结果 在慢查询的定义中,统计比较慢的时间段指的 ...

  9. C - Roads in the North DFS+树的直径

    Building and maintaining roads among communities in the far North is an expensive business. With thi ...

  10. 对短路变形POJ3615

    Farmer John wants the cows to prepare for the county jumping competition, so Bessie and the gang are ...