codevs 1225 八数码难题

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
题目描述 Description

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.
问题描述

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

283104765

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

详见试题

分类标签 Tags 点此展开

启发式搜索 广度优先搜索 深度优先搜索 迭代搜索 搜索
  1.  
  1. /*复杂题目模板加注解*/
  2. # include <stdio.h>
  3. # include <mem.h>
  4.  
  5. # define MAXN ( + )
  6.  
  7. typedef struct
  8. {
  9. char a[];
  10. }state;
  11.  
  12. const int dir[][] = {{-,}, {,}, {,}, {,-}};
  13. int fact[];
  14.  
  15. int front, rear;
  16. state cur, nst; /* new state */
  17. char vis[MAXN];
  18. char dist[MAXN]; /* 求的是最短距离( < 100),可以用 char 类型 */
  19. state Q[MAXN/];
  20.  
  21. void read(state *s);
  22. int inversions(state s);
  23. int cantor(state s);
  24. void init_fact(void);
  25. int bfs_d(state start, state goal);
  26.  
  27. int main()
  28. {
  29. state start, goal;
  30.  
  31. freopen("in.txt", "r", stdin);
  32. freopen("out.txt", "w", stdout);
  33.  
  34. init_fact();
  35.  
  36. read(&start);/*指针引用*/
  37. read(&goal);
  38.  
  39. if (inversions(start)% == inversions(goal)%)/
  40. {/*判断能不能到达最终状态,如果能达到最终状态的话,那么格子中的个数在后面有几个比他小的数的和的奇偶是不变的,无论怎么变换,可以用归纳推理证明*/
  41. printf("%d\n", bfs_d(start, goal));
  42. }
  43. else puts("-1");/*找不到最终的状态*/
  44.  
  45. return ;
  46. }
  47.  
  48. int bfs_d(state start, state goal)
  49. {
  50. int i, x, y, nx, ny, ct, nt;
  51.  
  52. memset(vis, , sizeof(vis));
  53. memset(dist, , sizeof(dist));
  54.  
  55. front = ;
  56. Q[front] = start;
  57. rear = ;
  58. Q[rear++] = goal;
  59. vis[cantor(start)] = ; /* 1 表示从起始节点扩展得到 */
  60. vis[cantor(goal)] = ; /* 2 表示从目标节点扩展得到 */
  61.  
  62. while (front < rear)
  63. {
  64. cur = Q[front++];
  65. ct = cantor(cur);
  66. for (i = ; cur.a[i] && i < ; ++i);/*找出0的位置*/
  67. x = i / ;/*求出0所在的行数列数*/
  68. y = i % ;
  69. for (i = ; i < ; ++i)
  70. {
  71. nx = x + dir[i][];/*把0向四周扩展*/
  72. ny = y + dir[i][];
  73. if (nx>= && nx< && ny>= && ny<)
  74. {
  75. nst = cur;
  76. nst.a[x*+y] = cur.a[nx*+ny];/*互换0的位置与对应元素的位置*/
  77. nst.a[nx*+ny] = ;
  78. if (!vis[nt = cantor(nst)])/*判断当前这个状态是否已经到过*/
  79. {
  80. Q[rear++] = nst;
  81. /* foot[nt] = ct; */
  82. dist[nt] = dist[ct] + ;
  83. vis[nt] = vis[ct];/*转移扩展的方向*/
  84. }
  85. else if (vis[ct] != vis[nt])/*如果已经到过,就是两者变换的次数和加上最后一次变化*/
  86. {/*这是双向广搜的精髓,判断两个点是从不同的方向转移来的*/
  87. return + dist[nt] + dist[ct];
  88. }
  89. }
  90. }
  91. }
  92.  
  93. return -;
  94. }
  95.  
  96. void read(state *s)
  97. {
  98. int i;
  99. char c[];
  100.  
  101. for (i = ; i < ; ++i)
  102. {
  103. scanf("%s", c);
  104. if (c[] == 'x') (*s).a[i] = ;
  105. else (*s).a[i] = c[] - '';
  106. }
  107. }
  108.  
  109. int inversions(state s)
  110. {
  111. char ch;
  112. int i, j, ret;
  113.  
  114. ret = ;
  115. for (i = ; i < ; ++i)
  116. {
  117. if (s.a[i] == ) continue;
  118. ch = s.a[i];
  119. for (j = i+; j < ; ++j)
  120. {
  121. if (s.a[j] < ch && s.a[j] != )
  122. ++ret;
  123. }
  124. }
  125.  
  126. return ret;
  127. }
  128.  
  129. int cantor(state s)/*康托展开应用于哈希表,处理排列问题是不会有冲突的,网上有证明,可以自己看*/
  130. {
  131. char ch;
  132. int i, j, ret, cnt;
  133.  
  134. ret = ;
  135. for (i = ; i < ; ++i)
  136. {
  137. cnt = ;
  138. ch = s.a[i];
  139. for (j = i+; j < ; ++j)
  140. {
  141. if (s.a[j] < ch)
  142. ++cnt;
  143. }
  144. ret += cnt*fact[-i];
  145. }
  146.  
  147. return ret;
  148. }
  149.  
  150. void init_fact(void)
  151. {
  152. int i;
  153.  
  154. fact[] = ;
  155. for (i = ; i < ; ++i)
  156. {
  157. fact[i] = i * fact[i-];/*处理阶乘,整张图一共有9!种状态*/
  158. }
  159. }
  1.  
  1.  

本题题解:

  1. #define N 3628800
  2. #include<iostream>
  3. #include<queue>
  4. #include<cstdio>
  5. #include<cstring>
  6. using namespace std;
  7. struct state{
  8. char a[];
  9. };
  10. queue<state>que;
  11. int xx[]={,,,-};
  12. int yy[]={,-,,};
  13. int visit[N]={};
  14. int fact[]={};
  15. int dis[N]={};
  16. void init_goal(state& goal)
  17. {
  18. goal.a[]='';goal.a[]='';goal.a[]='';
  19. goal.a[]='';goal.a[]='';goal.a[]='';
  20. goal.a[]='';goal.a[]='';goal.a[]='';
  21. //goal.a="123804765";
  22. //strcpy(goal.a,"123804765");
  23. }
  24. void in_fact()
  25. {
  26. fact[]=;
  27. for(int i=;i<;++i)
  28. fact[i]=i*fact[i-];
  29. }
  30. int cantor(state k)
  31. {
  32. int ret=;
  33. for(int i=;i<;++i)
  34. {
  35. int cnt=;
  36. char ch=k.a[i];
  37. for(int j=i+;j<;++j)
  38. if(ch>k.a[j]) cnt++;
  39. ret+=cnt*fact[-i];
  40. }
  41. return ret;
  42. }
  43. int bfs(state begin,state goal)
  44. {
  45. que.push(begin);que.push(goal);
  46. int k1=cantor(begin);
  47. int k2=cantor(goal);
  48. visit[k1]=;
  49. visit[k2]=;
  50. dis[k1]=;dis[k2]=;
  51. while(!que.empty())
  52. {
  53. state fro=que.front();
  54. int can_fro=cantor(fro);
  55. que.pop();
  56. int i;
  57. for(i=;fro.a[i]!=''&&i<;++i);
  58. int x=i/;
  59. int y=i%;
  60. for(int j=;j<;++j)
  61. {
  62. int nx=x+xx[j],ny=y+yy[j];
  63. if(nx>=&&nx<&&ny>=&&ny<)
  64. {
  65. state now=fro;
  66. now.a[*x+y]=fro.a[*nx+ny];
  67. now.a[*nx+ny]='';
  68. int kj=cantor(now);
  69. if(!visit[kj])
  70. {
  71. que.push(now);
  72. visit[kj]=visit[can_fro];/*转移是正向扩展还是逆向扩展*/
  73. dis[kj]=dis[can_fro]+;
  74. }
  75. else if(visit[kj]!=visit[can_fro])
  76. {/*这是双向广搜的精髓,必须用visit表示当前这个是同时由正反广搜扩展来的*/
  77. return +dis[kj]+dis[can_fro];
  78. }
  79. }
  80. }
  81. }
  82. }
  83. int main()
  84. {
  85. state goal,begin;
  86. init_goal(goal);
  87. in_fact();
  88. // scanf("%s",goal.a+1);
  89. scanf("%s",begin.a);
  90. printf("%d\n",bfs(begin,goal));
  91. return ;
  92. }

双向广搜+hash+康托展开 codevs 1225 八数码难题的更多相关文章

  1. Codevs 1225 八数码难题

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

  2. poj 3131 Cubic Eight-Puzzle 双向广搜 Hash判重

    挺不错的题目,很锻炼代码能力和调试能力~ 题意:初始格子状态固定,给你移动后格子的状态,问最少需要多少步能到达,如果步数大于30,输出-1. 由于单向搜索状态太多,搜到二十几就会爆了,所以应该想到双向 ...

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

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

  4. 双向广搜 codevs 3060 抓住那头奶牛

    codevs 3060 抓住那头奶牛 USACO  时间限制: 1 s  空间限制: 16000 KB  题目等级 : 黄金 Gold   题目描述 Description 农夫约翰被告知一头逃跑奶牛 ...

  5. 万圣节后的早晨&&九数码游戏——双向广搜

    https://www.luogu.org/problemnew/show/P1778 https://www.luogu.org/problemnew/show/P2578 双向广搜. 有固定起点终 ...

  6. HDU--杭电--1195--Open the Lock--深搜--都用双向广搜,弱爆了,看题了没?语文没过关吧?暴力深搜难道我会害羞?

    这个题我看了,都是推荐的神马双向广搜,难道这个深搜你们都木有发现?还是特意留个机会给我装逼? Open the Lock Time Limit: 2000/1000 MS (Java/Others)  ...

  7. 双向广搜 POJ 3126 Prime Path

      POJ 3126  Prime Path Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16204   Accepted ...

  8. 【双向广搜+逆序数优化】【HDU1043】【八数码】

    HDU上的八数码 数据强的一B 首先:双向广搜 先处理正向搜索,再处理反向搜索,直至中途相遇 visit 和 队列都是独立的. 可以用一个过程来完成这2个操作,减少代码量.(一般还要个深度数组) 优化 ...

  9. nyoj 523 双向广搜

    题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=523 #include<iostream> #include<cstd ...

随机推荐

  1. springMVC全局Exception异常处理SimpleMappingExceptionResolver

    继承了SimpleMappingExceptionResolver 贴上代码 /** * 对controller异常进行全局处理 * 区分了对普通请求和ajax请求的异常处理,普通请求返回到配置的er ...

  2. [python学习笔记]Day3

    函数 如: def is_leapyear(year): if (year%4 == 0 and year%100 != 0) or (year%400 == 0): return True else ...

  3. HttpController的激活

    Web API调用请求的目标是定义在某个HttpController类型中的某个Action方法,所以消息处理管道的最终需要激活目标HttpController对象.调用请求的URI会携带目标Http ...

  4. 控制台(Console)报错:java.io.IOException: Broken pipe

    控制台(Console)输出: java.io.IOException: Broken pipe at sun.nio.ch.FileDispatcherImpl.write0(Native Meth ...

  5. 【译】Dependency Injection with Autofac

    先说下为什么翻译这篇文章,既定的方向是架构,然后为了学习架构就去学习一些架构模式.设计思想. 突然有一天发现依赖注入这种技能.为了使得架构可测试.易维护.可扩展,需要架构设计为松耦合类型,简单的说也就 ...

  6. CSS文本溢出显示省略号

    项目中常常有这种需要我们对溢出文本进行"..."显示的操作,单行多行的情况都有(具体几行得看设计师心情了),这篇随笔是我个人对这种情况解决办法的归纳,欢迎各路英雄指教. 单行 语法 ...

  7. ArcGIS中的style样式的使用

    MapGIS安装包大小(以M计算)与ArcGIS (以G计算)在数量级存在差异,就可以隐约知道ArcGIS功能的强大.ArcGIS更注重重用(比如符号库.模块等).数据与制图分离(尤其是制图表达最能体 ...

  8. windows 8 设置hyper-v网络设置

    1 windwos 8 设置hyperv 比较简单,和装操作系统都不多做解释.我只多说说网络的设置问题,因为可能装提windows 2008虚拟机,根据网上设置网络的方式都是要不然只能虚拟 机上网 , ...

  9. [Microsoft Dynamics CRM 2016]Invalid Action – The selected action was not valid 错误的诱因及解决方法

    详细问题描述: 由于解决windows server 评估版过期\SQL server 评估版过期的问题后而导致的Invalid Action – The selected action was no ...

  10. 【读书笔记】iOS-类别

    一,类别是一种为现有的类添加新方法的方式. 二,类别的局限性. 1,无法向类中添加新的实例变量.类别没有位置容纳实例变量. 2,名称冲突,即类别中的方法与现有的方法重名.当发生名称冲突时,类别具有更高 ...