本题有写法好几个写法,但主要思路是BFS:

No。1

采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重。如果只进行单向会超时。

No。2

采用hash进行判重,宽搜采用单向就可以AC。

No。3

运用康拓展开进行判重,即使采用单向宽搜时间效率也很高。

哈希是想到了,但是我们应该选择什么哈希函数呢,看了网上一些神牛利用的是"康托展开",也就是利用全排列都有一个对应的整数,利用哈希函数把状态压缩成整数,这样就可以做到每一个整数都是唯一对应一个状态,那么这个时候就把哈希做完了。

  1. Eight
  2. Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
  3. Total Submission(s): 29838 Accepted Submission(s): 7831
  4. Special Judge
  5. Problem Description
  6. The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as:
  7. 1 2 3 4
  8. 5 6 7 8
  9. 9 10 11 12
  10. 13 14 15 x
  11. where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
  12. 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
  13. 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8
  14. 9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12
  15. 13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x
  16. r-> d-> r->
  17. The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
  18. Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
  19. frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
  20. In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
  21. arrangement.
  22. Input
  23. You will receive, several descriptions of configuration of the 8 puzzle. One description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle
  24. 1 2 3
  25. x 4 6
  26. 7 5 8
  27. is described by this list:
  28. 1 2 3 x 4 6 7 5 8
  29. Output
  30. You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line. Do not print a blank line between cases.
  31. Sample Input
  32. 2 3 4 1 5 x 7 6 8
  33. Sample Output
  34. ullddrurdllurdruldr
  35. Source
  36. South Central USA 1998 (Sepcial Judge Module By JGShining)

【代码】:

  1. #include<cstdio>
  2. #include<string>
  3. #include<cstdlib>
  4. #include<cmath>
  5. #include<iostream>
  6. #include<cstring>
  7. #include<set>
  8. #include<queue>
  9. #include<algorithm>
  10. #include<vector>
  11. #include<map>
  12. #include<cctype>
  13. #include<stack>
  14. #include<sstream>
  15. #include<list>
  16. #include<assert.h>
  17. #include<bitset>
  18. #include<numeric>
  19. #define debug() puts("+++++++++++++++++++++++++++++")
  20. #define gcd(a,b) __gcd(a,b)
  21. #define lson l,m,rt<<1
  22. #define rson m+1,r,rt<<1|1
  23. #define fi first
  24. #define se second
  25. #define pb push_back
  26. #define sqr(x) ((x)*(x))
  27. #define ms(a,b) memset(a,b,sizeof(a))
  28. #define sz size()
  29. #define be begin()
  30. #define pu push_up
  31. #define pd push_down
  32. #define cl clear()
  33. #define lowbit(x) -x&x
  34. #define all 1,n,1
  35. #define rep(i,x,n) for(int i=(x); i<(n); i++)
  36. #define in freopen("in.in","r",stdin)
  37. #define out freopen("out.out","w",stdout)
  38. using namespace std;
  39. typedef long long LL;
  40. typedef unsigned long long ULL;
  41. typedef pair<int,int> P;
  42. const int INF = 0x3f3f3f3f;
  43. const LL LNF = 1e18;
  44. const int maxn = 1000000;
  45. const int maxm = 1e6 + 10;
  46. const double PI = acos(-1.0);
  47. const double eps = 1e-8;
  48. const int dx[] = {-1,1,0,0,1,1,-1,-1};
  49. const int dy[] = {0,0,1,-1,1,-1,1,-1};
  50. const int d[6][3]={ {0,0,1},{0,0,-1},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0} };
  51. int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
  52. const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  53. const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  54. int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
  55. bool vis[maxn];
  56. int cantor(int *s) //康拖展开求该序列的hash值
  57. {
  58. int sum = 0;
  59. for(int i=0; i<9; i++)
  60. {
  61. int num = 0;
  62. for(int j=i+1; j<9; j++)
  63. if(s[j] < s[i]) num++;
  64. sum += (num*fac[9-i-1]);
  65. }
  66. return sum + 1;
  67. }
  68. struct node
  69. {
  70. int s[9]; //数位- 2 3 4 1 5 x-0 7 6 8
  71. int loc; //“0”的位置,把“x"当0
  72. int status; //康拖展开的hash值
  73. string path; //路径
  74. }st,ed,now;
  75. string path;
  76. int aim = 46234; //123456780对应的康拖展开的hash值
  77. char indexs[5]="udlr"; //正向搜索
  78. bool check(int tx,int ty)
  79. {
  80. return (tx<0||tx>2||ty<0||ty>2);
  81. }
  82. bool bfs()
  83. {
  84. ms(vis,0);
  85. queue<node> q;
  86. q.push(now);
  87. while(!q.empty())
  88. {
  89. st = q.front();
  90. q.pop();
  91. if(st.status==aim)
  92. {
  93. path = st.path;
  94. return true;
  95. }
  96. int x = st.loc/3;
  97. int y = st.loc%3;
  98. for(int i=0; i<4; i++)
  99. {
  100. //0和四周交换
  101. int tx = x + dir[i][0];
  102. int ty = y + dir[i][1];
  103. if(check(tx,ty)) continue;
  104. ed = st;
  105. ed.loc = tx * 3 + ty; //0和四周交换
  106. ed.s[st.loc] = ed.s[ed.loc];
  107. ed.s[ed.loc] = 0;
  108. ed.status = cantor(ed.s);
  109. if(!vis[ed.status])
  110. {
  111. vis[ed.status] = true;
  112. ed.path+=indexs[i];
  113. if(ed.status==aim)
  114. {
  115. path=ed.path;
  116. return true;
  117. }
  118. q.push(ed);
  119. }
  120. }
  121. }
  122. return false;
  123. }
  124. /*
  125. 2 3 4 1 5 x 7 6 8
  126. ullddrurdllurdruldr
  127. */
  128. int main()
  129. {
  130. char ch;
  131. while(cin>>ch)
  132. {
  133. if(ch=='x') {now.s[0]=0; now.loc=0;}
  134. else now.s[0]=ch-'0';
  135. for(int i=1;i<9;i++)
  136. {
  137. cin>>ch;
  138. if(ch=='x')
  139. {
  140. now.s[i]=0;
  141. now.loc=i;
  142. }
  143. else now.s[i]=ch-'0';
  144. }
  145. now.status=cantor(now.s);//234150768——>
  146. if(bfs()) cout<<path<<endl;
  147. else cout<<"unsolvable"<<endl;
  148. }
  149. }

  1. //思路: 单向bfs()+哈希判重+路径输出(由于POJ数据只有一组,这个方法可以在POJ上面A,其它oj不能A )
  2. #include <algorithm>
  3. #include <iostream>
  4. #include <cstring>
  5. #include <string>
  6. #include <vector>
  7. #include <cstdio>
  8. #include <cctype>
  9. #include <stack>
  10. #include <queue>
  11. #include <cmath>
  12. using namespace std;
  13. #define MAXN 400000
  14. struct State{
  15. int state[9];
  16. int pos;//空格位置
  17. char ch[50];//记录原始状态到达当前状态的路径(数组不能开太大不然超内存)
  18. }s[MAXN];//每一个状态对应一个结构体
  19. int factor[9] = {1,1,2,6,24,120,720,5040,40320};//阶乘数组
  20. int dir[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};//方向数组
  21. char dirtion[4] = {'u' , 'r' , 'd' , 'l'};
  22. int vis[MAXN];//标记某个状态是否被走过
  23. int start;//保存原始输入状态的哈希值
  24. State star;//原始状态对应的结构体
  25. queue<int>q;//这里不能直接放结构体,不然肯定超时
  26. //哈希映射
  27. int Hash(int s[]){
  28. int i , j , temp , num;
  29. num = 0 ;
  30. for(i = 0 ; i < 9 ; i++){
  31. temp = 0;
  32. for(j = i+1 ; j < 9 ; j++){
  33. if(s[j] < s[i]) temp++;
  34. }
  35. num += factor[8-i]*temp;
  36. }
  37. return num;
  38. }
  39. //广搜
  40. bool Bfs(){
  41. while(!q.empty()) q.pop();
  42. memset(vis , 0 , sizeof(vis));
  43. start = Hash(star.state);
  44. vis[start] = 1;
  45. s[start] = star;
  46. q.push(start);
  47. while(!q.empty()){
  48. State cur = s[q.front()];
  49. q.pop();
  50. int x , y , r , c;
  51. x = cur.pos/3 ; y = cur.pos%3;
  52. for(int i = 0 ; i < 4 ; i++){
  53. r = x+dir[i][0] ; c = y+dir[i][1];
  54. if(r < 0 || c < 0 || r >= 3 || c >= 3) continue;
  55. State tmp = cur;
  56. tmp.state[tmp.pos] = tmp.state[3*r+c];//原先空格位置换成新的编号
  57. tmp.pos = 3*r+c ; tmp.state[tmp.pos] = 9;//重新更新空格位置
  58. int hash = Hash(tmp.state);//求出当前哈希值
  59. if(vis[hash]) continue;
  60. vis[hash] = 1;
  61. int len = strlen(cur.ch);//求出前一个状态的路径长度
  62. tmp.ch[len] = dirtion[i];//更新路径
  63. s[hash] = tmp;//赋值
  64. if(hash == 0){//如果搜索到目标节点直接输出退出
  65. printf("%s\n" , s[hash].ch) ; return 1;
  66. }
  67. q.push(hash);//入对列
  68. }
  69. }
  70. return 0;
  71. }
  72. int main(){
  73. char c;
  74. while(scanf("%c" , &c) != EOF){
  75. if(c == 'x'){ star.state[0] = 9 ; star.pos = 0;}
  76. else star.state[0] = c-'0';
  77. for(int i = 1 ; i < 9 ; i++){
  78. scanf(" %c" , &c);
  79. if(c == 'x'){ star.pos = i ; star.state[i] = 9;}
  80. else star.state[i] = c-'0';
  81. }
  82. getchar();
  83. int flag = Bfs();
  84. if(!flag) printf("unsolvable\n");//无解的情况
  85. }
  86. return 0;
  87. }

HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】的更多相关文章

  1. hdu 1043 Eight 经典八数码问题

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 The 15-puzzle has been around for over 100 years ...

  2. HDU 1043 Eight(八数码)

    HDU 1043 Eight(八数码) 00 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)   Problem Descr ...

  3. hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】

    <题目链接> 题目大意:给出一个3×3的矩阵(包含1-8数字和一个字母x),经过一些移动格子上的数后得到连续的1-8,最后一格是x,要求最小移动步数. 解题分析:本题用BFS来寻找路径,为 ...

  4. 八数码问题+路径寻找问题+bfs(隐式图的判重操作)

    Δ路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条凑够初始状态到终止问题的最优路径, 而不是像回溯法那样找到一个符合某些要求的解. 八数码问题就是路径查找问题背景下的经典训练题目. 程序框架 p ...

  5. hdu 1043(经典搜索)

    题意: 给你一个初始的图,然后每次输入一个图,要求移动x最小的步数达到和初始图一样,输出路径 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 ...

  6. hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数

    题意: 题意就是八数码,给了一个3 * 3 的矩阵,上面有八个数字,有一个位置是空的,每次空的位置可以和他相邻的数字换位置,给你一些起始状态 ,给了一个最终状态,让你输出怎么变换才能达到目的. 思路: ...

  7. hdu Minimum Transport Cost(按字典序输出路径)

    http://acm.hdu.edu.cn/showproblem.php? pid=1385 求最短路.要求输出字典序最小的路径. spfa:拿一个pre[]记录前驱,不同的是在松弛的时候.要考虑和 ...

  8. HDU1043 Eight(八数码:逆向BFS打表+康托展开)题解

    Eight Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  9. HDOJ-1043 Eight(八数码问题+双向bfs+高效记录路径+康拓展开)

    bfs搜索加记录路径 HDOJ-1043 主要思路就是使用双向广度优先搜索,找最短路径.然后记录路径,找到结果是打印出来. 使用康拓序列来来实现状态的映射. 打印路径推荐使用vector最后需要使用a ...

随机推荐

  1. 设置select和option的文字居中的方法

    给select设置text-align:center在火狐浏览器下ok,但是在chrome浏览器无效,然后option在两个浏览器下设置text-align:center都是无效的,解决方法,设置样式 ...

  2. Hibernate常用方法之_修改

    1.使用session的saveOrUpdate方法 public void updateUser(User user){ Session session = null; Transaction tr ...

  3. Div+Css中transparent制作奥运五环

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. # centos7下FFmpeg环境部署记录

    # centos7下FFmpeg环境部署记录 随着视频在网站上的应用越来越多,越来越多的网站服务器需要支持视频转码,视频压缩,FFmpeg是目前最好用的网站服务器后台转码程序,应用最多.FFmpeg是 ...

  5. [Leetcode] Best time to buy and sell stock 买卖股票的最佳时机

    Say you have an array for which the i th element is the price of a given stock on day i. If you were ...

  6. Codeforces Round #524 (Div. 2) C. Masha and two friends

    C. Masha and two friends 题目链接:https://codeforc.es/contest/1080/problem/C 题意: 给出一个黑白相间的n*m的矩阵,现在先对一个子 ...

  7. Welcome to ShangHai <码农上漂记>

    来上海这边快三周了,一切都还算顺利,多亏了朋友们的帮助,要不就得街头打地铺了.对于上海这样的大都市,年轻的我们都想挤一挤,凑凑热闹,实现自己的小小抱负.然而不是每个人都混的起的.以前的我还总想着来大城 ...

  8. missing blocks错误

    Datanode的日志中看到: 10/12/14 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXX ...

  9. 迅雷Bolt的ClipSubBindBitmap函数特别说明

    因为在工作中基于迅雷Bolt开发的是IM产品,需要实现自定义用户头像的功能. 但Bolt中对图像的默认拉伸锯齿效果非常明显,所以自己实现了图像拉伸函数,代码已共享,具体可查看:<迅雷Bolt图像 ...

  10. 转:Linux下使用Nginx搭建简单图片服务器

    最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的,今天再这里简单讲一下Nginx实现上传图片以及图片服务器的大致理念. 如果是个人项目或者企业小项目,仅 ...