题目:八数码

网址: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. P - Sudoku Killer HDU - 1426(dfs + map统计数据)

    P - Sudoku Killer HDU - 1426 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视. 据说,在2008北京奥运会上,会将数独列为 ...

  2. 在ES5实现ES6中的Object.is方法

    ES6中对象的扩展里面添加了一个Object.is方法,用于比较两个值是否严格相等.内部计算与 === 行为基本一致.那么我们怎么在不支持这个方法的ES5中实现呢? 首先我们需要搞清楚两点,1:Obj ...

  3. Wireshark的使用(抓包、过滤器)

    Wireshark的使用(抓包.过滤器) 听语音 分步阅读 Wireshark这个转包工具的简单实用 工具/原料 Wireshark软件包 方法/步骤 Wireshark是世界上最流行的网络分析工具. ...

  4. Jmeter 压力测试笔记(1)--服务器迁移失败

    近期,公司服务器因技术架构升级等原因需要迁移,在经过开发,运维DBA,测试多部门进行联合讨论后,制定出了迁移方案.迁移前也对APP应用进行了各种测试,并没有发现问题. 凌晨2点开始迁移,5点完成迁移. ...

  5. 好玩Python——PIL项目实训

    PIL学习总结: 1. 2,PIL库概述: pil库可以完成图像归档和图像处理两方面功能的需求: 图像归档:对图像进行批处理,生成图像预览,图像转换格式等: 图像处理:图像基本处理,像素处理,颜色处理 ...

  6. 家庭版记账本app进度之对于按钮的点击事件以及线性布局以及(alertdialog)等相关内容的应用测试

    通过线性布局,制作出连个按钮还有文本输入框以及嘴上放的标题文本进行信息的相关显示,完后最后的信息的输入,之后在屏幕的的下方进行显示 当点击第一个按钮的时候,在下方就会简单的出现你自己刚刚输入的相关信息 ...

  7. MTK Android Driver :Battery电池曲线

    MTK Android Driver :battery电池曲线 1.配置文件位置: CUSTOM_KERNEL_BATTERY= battery mediatek\custom\\kernel\bat ...

  8. linux系统管理,查看系统资源

    free 查看内存使用情况 -b  ===>  以byte为单位 -k  ===>  以Kb为单位 -m  ===>  以Mb为单位 -g  ===>  以Gb为单位 -t  ...

  9. python的int float if...else

    # 字符串 string  单引号 ‘ ’  双引号 “  ”-包含的 app = 'dongt woory' 外面单引号里面可以双引号,外面双引号,里面也可以单引号 app ='你是真的“好看”吗' ...

  10. hexo部署在码云中 无样式问题

    在本地localhost:4000 运行如下 上传码云之后打开Gitee Pages服务 如下 同时控制台打印 解决方法 找到根目录下的_config.yml中的url 和 root # url: h ...