题目:八数码

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

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

例如:

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

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

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

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

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

交换过程如下:

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

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

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

输入格式

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

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

  1. 1 2 3
  2. x 4 6
  3. 7 5 8

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

输出格式

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

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

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

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

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

STL代码如下:

  1. #include<iostream>
  2. #include<sstream>
  3. #include<cstring>
  4. #include<string>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<queue>
  8. #include<map>
  9. #include<set>
  10. #define pii pair <int, int>
  11. using namespace std;
  12. const int dx[4] = {-1, 1, 0, 0};
  13. const int dy[4] = {0, 0, -1, 1};
  14. int st, ed = 123456780;
  15. set <int> vis;
  16. map <int, int> d, f;
  17. void decode(int state, int *p)
  18. {
  19. for(int i = 0; i < 9; ++ i)
  20. {
  21. p[8 - i] = state % 10;
  22. state /= 10;
  23. }
  24. return;
  25. }
  26. int encode(int *p)
  27. {
  28. int t = 0;
  29. for(int i = 0; i < 9; ++ i)
  30. {
  31. t = (t << 3) + (t << 1);
  32. t += p[i];
  33. }
  34. return t;
  35. }
  36. int gh(int *p)
  37. {
  38. int cost = 0;
  39. for(int i = 0; i < 9; ++ i)
  40. cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3);
  41. return cost;
  42. }
  43. void print(int state)
  44. {
  45. if(state == st) return;
  46. int pre_state = f[state];
  47. print(pre_state);
  48. int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
  49. decode(state, p1), decode(pre_state, p2);
  50. for(i = 0; i < 9; ++ i)
  51. {
  52. if(p1[i] == 0)
  53. {
  54. t1 = i;
  55. break;
  56. }
  57. }
  58. for(i = 0; i < 9; ++ i)
  59. {
  60. if(p2[i] == 0)
  61. {
  62. t2 = i;
  63. break;
  64. }
  65. }
  66. if(t1 < t2)
  67. {
  68. if(t1 - t2 == -1) putchar('l');
  69. else putchar('u');
  70. }
  71. else
  72. {
  73. if(t2 - t1 == -1) putchar('r');
  74. else putchar('d');
  75. }
  76. return;
  77. }
  78. bool valid(int x, int y)
  79. {
  80. if(x < 0 || x > 2 || y < 0 || y > 2) return false;
  81. return true;
  82. }
  83. bool hash_table_judge(int state)
  84. {
  85. if(vis.count(state)) return false;
  86. return true;
  87. }
  88. void hash_table_insert(int next_state, int state)
  89. {
  90. d[next_state] = d[state] + 1;
  91. vis.insert(next_state);
  92. f[next_state] = state;
  93. return;
  94. }
  95. int bfs()
  96. {
  97. if(st == ed) return 0;
  98. d.clear(), vis.clear(), f.clear();
  99. queue <int> Q;
  100. while(!Q.empty()) Q.pop();
  101. int state, next_state, now, next, p[9], x, y;
  102. memset(p, -1, sizeof(p));
  103. hash_table_insert(st, 0);
  104. d[st] = 0;
  105. Q.push(st);
  106. while(!Q.empty())
  107. {
  108. state = Q.front();
  109. Q.pop();
  110. decode(state, p);
  111. for(int i = 0; i < 9; ++ i)
  112. {
  113. if(p[i] == 0)
  114. {
  115. now = i;
  116. x = i / 3, y = i % 3;
  117. break;
  118. }
  119. }
  120. for(int i = 0; i < 4; ++ i)
  121. {
  122. if(!valid(x + dx[i], y + dy[i])) continue;
  123. next = (x + dx[i]) * 3 + (y + dy[i]);
  124. swap(p[now], p[next]);
  125. next_state = encode(p);
  126. swap(p[now], p[next]);
  127. if(!hash_table_judge(next_state)) continue;
  128. hash_table_insert(next_state, state);
  129. if(next_state == ed)
  130. {
  131. printf("%d\n", d[state]);
  132. print(state);
  133. return 1;
  134. }
  135. Q.push(next_state);
  136. }
  137. }
  138. return -1;
  139. }
  140. int main()
  141. {
  142. string line;
  143. getline(cin, line);
  144. for(int i = 0; i < line.size(); ++ i)
  145. {
  146. if(line[i] == 'x')
  147. {
  148. line[i] = '0';
  149. break;
  150. }
  151. }
  152. stringstream ss(line);
  153. int tmp;
  154. st = 0;
  155. for(int i = 0; i < 9; ++ i)
  156. {
  157. ss >> tmp;
  158. st = (st << 3) + (st << 1);
  159. st += tmp;
  160. }
  161. if(bfs() == -1) puts("unsolvable");
  162. return 0;
  163. }

hash表代码如下:

  1. #include<iostream>
  2. #include<sstream>
  3. #include<cstring>
  4. #include<string>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<queue>
  8. #include<map>
  9. #define pii pair <int, int>
  10. using namespace std;
  11. const int maxn = 377777 + 5, mod = 377777;
  12. const int dx[4] = {-1, 1, 0, 0};
  13. const int dy[4] = {0, 0, -1, 1};
  14. int st, ed = 123456780, head[maxn] = {}, next[maxn] = {}, table[maxn] = {}, tot = 0;
  15. map <int, int> d, f;
  16. void decode(int state, int *p)
  17. {
  18. for(int i = 0; i < 9; ++ i)
  19. {
  20. p[8 - i] = state % 10;
  21. state /= 10;
  22. }
  23. return;
  24. }
  25. int encode(int *p)
  26. {
  27. int t = 0;
  28. for(int i = 0; i < 9; ++ i)
  29. {
  30. t = (t << 3) + (t << 1);
  31. t += p[i];
  32. }
  33. return t;
  34. }
  35. int hash_table_search(int state)
  36. {
  37. int val = state % mod;
  38. for(int i = head[val]; i; i = next[i])
  39. if(table[i] == state) return i;
  40. return -1;
  41. }
  42. int gh(int *p)
  43. {
  44. int cost = 0;
  45. for(int i = 0; i < 9; ++ i)
  46. cost += abs(i / 3 - (p[i] - 1) / 3) + abs(i % 3 - (p[i] - 1) % 3);
  47. return cost;
  48. }
  49. void print(int state)
  50. {
  51. if(state == st) return;
  52. int pre_state = f[state];
  53. print(pre_state);
  54. int i, p1[9] = {}, p2[9] = {}, t1 = -1, t2 = -1;
  55. decode(state, p1), decode(pre_state, p2);
  56. for(i = 0; i < 9; ++ i)
  57. {
  58. if(p1[i] == 0)
  59. {
  60. t1 = i;
  61. break;
  62. }
  63. }
  64. for(i = 0; i < 9; ++ i)
  65. {
  66. if(p2[i] == 0)
  67. {
  68. t2 = i;
  69. break;
  70. }
  71. }
  72. if(t1 < t2)
  73. {
  74. if(t1 - t2 == -1) putchar('l');
  75. else putchar('u');
  76. }
  77. else
  78. {
  79. if(t2 - t1 == -1) putchar('r');
  80. else putchar('d');
  81. }
  82. return;
  83. }
  84. bool valid(int x, int y)
  85. {
  86. if(x < 0 || x > 2 || y < 0 || y > 2) return false;
  87. return true;
  88. }
  89. bool hash_table_judge(int state)
  90. {
  91. int val = state % mod;
  92. for(int i = head[val]; i; i = next[i])
  93. if(table[i] == state) return false;
  94. return true;
  95. }
  96. void hash_table_insert(int next_state, int state)
  97. {
  98. int val = next_state % mod;
  99. table[++ tot] = next_state;
  100. next[tot] = head[val];
  101. head[val] = tot;
  102. f[next_state] = state;
  103. d[next_state] = d[state] + 1;
  104. return;
  105. }
  106. int bfs()
  107. {
  108. if(st == ed) return 0;
  109. d.clear(), f.clear();
  110. queue <int> Q;
  111. while(!Q.empty()) Q.pop();
  112. int state, next_state, now, next, p[9], x, y;
  113. memset(p, -1, sizeof(p));
  114. hash_table_insert(st, 0);
  115. d[st] = 0;
  116. Q.push(st);
  117. while(!Q.empty())
  118. {
  119. state = Q.front();
  120. Q.pop();
  121. decode(state, p);
  122. for(int i = 0; i < 9; ++ i)
  123. {
  124. if(p[i] == 0)
  125. {
  126. now = i;
  127. x = i / 3, y = i % 3;
  128. break;
  129. }
  130. }
  131. for(int i = 0; i < 4; ++ i)
  132. {
  133. if(!valid(x + dx[i], y + dy[i])) continue;
  134. next = (x + dx[i]) * 3 + (y + dy[i]);
  135. swap(p[now], p[next]);
  136. next_state = encode(p);
  137. swap(p[now], p[next]);
  138. if(!hash_table_judge(next_state)) continue;
  139. hash_table_insert(next_state, state);
  140. if(next_state == ed)
  141. {
  142. print(state);
  143. return d[state];
  144. }
  145. Q.push(next_state);
  146. }
  147. }
  148. return -1;
  149. }
  150. int main()
  151. {
  152. string line;
  153. getline(cin, line);
  154. for(int i = 0; i < line.size(); ++ i)
  155. {
  156. if(line[i] == 'x')
  157. {
  158. line[i] = '0';
  159. break;
  160. }
  161. }
  162. stringstream ss(line);
  163. int tmp;
  164. st = 0;
  165. for(int i = 0; i < 9; ++ i)
  166. {
  167. ss >> tmp;
  168. st = (st << 3) + (st << 1);
  169. st += tmp;
  170. }
  171. if(bfs() == -1) puts("unsolvable");
  172. return 0;
  173. }

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. I、恋爱之子

    链接:https://ac.nowcoder.com/acm/contest/3570/I 来源:牛客网 题目描述 最近ZSC和他的女朋友NULL吵架了.因为ZSC是一个直男,他不知道该怎么办,于是他 ...

  2. 开学java的初步考试

    //第一个.java文件 package project1; //20183777 温学智 信1805-2 public class ScoreInformation { private String ...

  3. 汇编刷题:内存 MEM 单元开始存放着 10 个带符号字节数据, 编写完整程序求其中正数、 零和负数的个 数, 并分别将它们存于 PLUS、 ZERO 和 NEGO 3 个单元

    DATA SEGMENT MEM DB 12H,91H,73H,64H,20H,0A5H,0D1H,91H,0A2H,00H PLUS DB 00H ZERO DB 00H NEGO DB 00H D ...

  4. javascript入门 之 zTree(十一 托拽事件(一))

    <!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO - drag & drop</TITLE ...

  5. JAVA中使用Date和SimpleDateFromat类表示时间

    转自:https://www.imooc.com/code/2335 仅做个人学习保存之用,侵删! 在程序开发中,经常需要处理日期和时间的相关数据,此时我们可以使用 java.util 包中的 Dat ...

  6. 内存对齐 align

    /* 地址对齐:指的是存放数据的首地址%N==0,而且整个结构体的大小%M(结构体的有效对齐值)==0 1 数据类型的自身对齐值:char:1 short:2 int,flolat,double:4 ...

  7. AJ学IOS 之微博项目实战(2)微博主框架-自定义导航控制器NavigationController

    AJ分享,必须精品 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController). 为啥要做自定义呢,因为为了更好地封 ...

  8. AJ学IOS(26)UI之iOS抽屉效果小Demo

    AJ分享,必须精品 先看效果 实现过程 第一步,把三个view设置好,还有颜色 #warning 第一步 - (void)addChildView { // left UIView *leftView ...

  9. Docker-准备Docker环境

    1. 前言 要学习Docker,首先要搭建出虚拟机和docker环境.我的笔记本电脑是windows7系统,用VirtualBox创建虚拟机.虚拟机操作系统为CentOS7.5,Docker版本为18 ...

  10. 用three.js开发三维地图实例

    公司要做智慧消防楼层可视化,需要用到web3d,开源的引擎中先研究了cesium三维地球,但cesium做楼层感觉是大材小用,而且体验也不好,最终选用的是功能强大.更适合小型场景的three. thr ...