BFS将近两年没练过题了,今天重新回忆下以前刷的蓝桥杯题:九宫格重排

样例输入 

  1. //初始状态
  2.  
  3. //终点状态

样例输出 

  1. //最短步数

样例输入 

  1. //初始状态
  2. //终点状态

样例输出 

  1. //最短步数

思路

以下图为例,空格0可以走上下左右4步 :

当前0位于的位置是(1,1),所以可以移动到(1-1,1),(1,1+1),(1+1,1),(1,1-1)

然后通过康拓展开来校验,移动的位置是否走过,是否已到终点,是否越界。

康拓展开

表示的是当前排列在n个不同元素的全排列中的名次.

公式为:

  1. X=a[n]*(n-)!+a[n-]*(n-)!+...+a[i]*(i-)!+...+a[]*!+a[]*!
  2. //a[i]为当前未出现的元素中是排在第几个(从0开始 )

比如,3124 是1~4全排列的第几个?(从0开始,比如1234是1~4全排列第0个)

  1. X=*!+ *!+ *!+ *!=
  • 第一位,在未出现的元素(1,2,3,4)中,只有2个数(1和2)比它小,位2~4全排列有3!个,所以=2*3!
  • 第一位3,第二位1, 1在未出现的元素(1,2,4)中,只有0个数比它小,位3~4全排列有2!个,所以=0*2!
  • 第一位3,第二位1,第三位, 2在未出现的元素(2,4)中,只有0个数比它小,所以=0*1!
  • 第一位,第二位,第三位, 第四位,4在未出现的元素(4)中,只有0个数比它小,所以=0*0!

康拓展开代码(s[4]={3,1,2,4},n=4)

  1. long int fac[]={,,,,,,,,,};//阶乘表
  2.  
  3. int congtuo(int s[],int n)
  4. {
  5. int i,j,temp,num;
  6. num=;
  7. for(i=;i<n;i++)
  8. {
  9. temp=;
  10.  
  11. for(int j=i+;j<n;j++)
  12. if(s[j]<s[i]) //判断几个数小于它
  13. temp++;
  14.  
  15. num+=fac[n-i-]*temp;
  16. }
  17.  
  18. return num;
  19. }

九宫格代码如下,纯手打勿喷:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. long int fac[]={,,,,,,,,,};//阶乘表
  5.  
  6. unsigned char step[]={}; // 9!=362880,所以数组要大点
  7.  
  8. char method[][]={{-,},{,},{,},{,-}}; //4种移动方法
  9.  
  10. struct node_t{
  11. unsigned char data[];
  12. };
  13.  
  14. struct node_t save_step[]; //保存移动数据,最多有 9!个移动数据
  15.  
  16. unsigned char end_p[]; //终点位置
  17.  
  18. int congtuo(unsigned char s[],int n)
  19. {
  20. int i,j,temp,num;
  21. num=;
  22. for(i=;i<n;i++)
  23. {
  24. temp=;
  25. for(int j=i+;j<n;j++)
  26. if(s[j]<s[i]) //判断几个数小于它
  27. temp++;
  28. num+=fac[n-i-]*temp;
  29. }
  30. return num;
  31. }
  32.  
  33. /*处理0函数
  34. *返回值0:交换的位置非法,或被走过
  35. *返回值1:没被走过
  36. *返回值2:找到终点
  37. */
  38. int handler_zero(int i,unsigned char data[])
  39. {
  40. int x,y,temp,num;
  41.  
  42. for(int j=;j<;j++)
  43. if(data[j]==)
  44. {
  45. /*[x,y]:需要交换的位置*/
  46. x=j%+method[i][];
  47. y=j/+method[i][];
  48.  
  49. /*判断交换位置是否越界*/
  50. if(x<||x>)
  51. return ;
  52. else if(y<||y>)
  53. return ;
  54.  
  55. /*判断交换后的位置是否已被走过*/
  56. data[j]= data[x+y*];
  57. data[x+y*]=;
  58. num=congtuo(data,);
  59. if(step[num]==) //已被走过
  60. {
  61. return ;
  62. }
  63.  
  64. if(memcmp(end_p,data,)==) //找到终点
  65. {
  66. return ;
  67. }
  68. step[num]=;
  69. return ;
  70. }
  71. }
  72.  
  73. int start=,end=;
  74. int bfs(void)
  75. {
  76. int x,y;
  77. int next_end=end; //存放下个位置的标志位
  78. int err;
  79. unsigned char temp[];
  80. for(;start<=end;start++)
  81. {
  82. for(int i=;i<;i++) //4种走法
  83. {
  84. memcpy(temp,(unsigned char *)save_step[start].data,);
  85.  
  86. err=handler_zero(i,temp); //处理数据里的0
  87.  
  88. if(err) //保存数据
  89. {
  90. memcpy((unsigned char *)save_step[++next_end].data,temp,);
  91.  
  92. if(err==) //找到终点
  93. return ;
  94. }
  95. }
  96. }
  97. start=end+;
  98. end=next_end;
  99. return (+bfs());
  100. }
  101.  
  102. int main()
  103. {
  104. int step_num=; //步数
  105. unsigned char s[];
  106.  
  107. printf("please enter start point:\r\n");
  108. for(int i=;i<;i++)
  109. {
  110. scanf("%1d",&save_step[].data[i]);
  111. }
  112.  
  113. printf("please enter end point:\r\n");
  114. for(int i=;i<;i++)
  115. {
  116. scanf("%1d",&end_p[i]);
  117. }
  118. step_num=bfs();
  119.  
  120. printf("%d\n",step_num);
  121.  
  122. }

如果想看走的步数具体内容,该怎么办?

其实很简单,因为具体内容都保存在save_step[]里,我们只需要在node_t结构体里多定义一个标志位step_p,来指向上次步数的位置在哪.

代码如下:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. long int fac[]={,,,,,,,,,};//阶乘表
  5.  
  6. unsigned char step[]={}; // 9!=362880,所以数组要大点
  7.  
  8. char method[][]={{-,},{,},{,},{,-}}; //4种移动方法
  9.  
  10. struct node_t{
  11. unsigned char data[];
  12. unsigned int step_p;
  13. };
  14.  
  15. struct node_t save_step[]; //保存移动数据,最多有 9!个移动数据
  16.  
  17. unsigned char end_p[]; //终点坐标
  18.  
  19. unsigned int end_index; //记录终点位置
  20.  
  21. int congtuo(unsigned char s[],int n)
  22. {
  23. int i,j,temp,num;
  24. num=;
  25. for(i=;i<n;i++)
  26. {
  27. temp=;
  28. for(int j=i+;j<n;j++)
  29. if(s[j]<s[i]) //判断几个数小于它
  30. temp++;
  31. num+=fac[n-i-]*temp;
  32. }
  33. return num;
  34. }
  35.  
  36. /*处理0函数
  37. *返回值0:交换的位置非法,或被走过
  38. *返回值1:没被走过
  39. *返回值2:找到终点
  40. */
  41. int handler_zero(int i,unsigned char data[])
  42. {
  43. int x,y,temp,num;
  44.  
  45. for(int j=;j<;j++)
  46. if(data[j]==)
  47. {
  48. /*[x,y]:需要交换的位置*/
  49. x=j%+method[i][];
  50. y=j/+method[i][];
  51.  
  52. /*判断交换位置是否越界*/
  53. if(x<||x>)
  54. return ;
  55. else if(y<||y>)
  56. return ;
  57.  
  58. /*判断交换后的位置是否已被走过*/
  59. data[j]= data[x+y*];
  60. data[x+y*]=;
  61. num=congtuo(data,);
  62. if(step[num]==) //已被走过
  63. {
  64. return ;
  65. }
  66.  
  67. if(memcmp(end_p,data,)==) //找到终点
  68. {
  69. return ;
  70. }
  71.  
  72. step[num]=;
  73. return ;
  74. }
  75. }
  76.  
  77. int start=,end=;
  78. int bfs(void)
  79. {
  80. int x,y;
  81. int next_end=end; //存放下次bfs的end标志位
  82. int err;
  83. unsigned char temp[];
  84.  
  85. for(;start<=end;start++)
  86. {
  87. for(int i=;i<;i++) //4种走法
  88. {
  89. memcpy(temp,(unsigned char *)save_step[start].data,);
  90.  
  91. err=handler_zero(i,temp); //处理数据里的0
  92.  
  93. if(err) //保存数据
  94. {
  95. memcpy((unsigned char *)save_step[++next_end].data,temp,);
  96.  
  97. save_step[next_end].step_p=start; //记录上次步数位置.
  98.  
  99. if(err==) //找到终点
  100. {
  101. end_index=next_end; //记录终点步数位置.
  102. return ;
  103. }
  104. }
  105. }
  106. }
  107. start=end+;
  108. end=next_end;
  109. return (+bfs());
  110. }
  111.  
  112. int main()
  113. {
  114. int step_num=; //步数
  115. unsigned char s[];
  116.  
  117. printf("please enter start point:\r\n");
  118. for(int i=;i<;i++)
  119. {
  120. scanf("%1d",&save_step[].data[i]);
  121. }
  122.  
  123. printf("please enter end point:\r\n");
  124. for(int i=;i<;i++)
  125. {
  126. scanf("%1d",&end_p[i]);
  127. }
  128.  
  129. step_num=bfs();
  130. printf("%d\n",step_num);
  131.  
  132. /**打印步数具体内容**/
  133. for(;step_num>=;step_num--)
  134. {
  135. printf("**step %d********\n",step_num);
  136. for(int i=;i<;i++)
  137. {
  138. printf("%d %d %d\n",save_step[end_index].data[i*],
  139. save_step[end_index].data[i*+],
  140. save_step[end_index].data[i*+]);
  141. }
  142. end_index=save_step[end_index].step_p;
  143. printf("\n");
  144. }
  145.  
  146. }

打印结果

BFS-九宫格重排(详解)的更多相关文章

  1. BFS和DFS详解

    BFS和DFS详解以及java实现 前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问 ...

  2. BFS和DFS详解以及java实现

    前言 图在算法世界中的重要地位是不言而喻的,曾经看到一篇Google的工程师写的一篇<Get that job at Google!>文章中说到面试官问的问题中几乎有一半的问题都可以用图的 ...

  3. Leetcode之广度优先搜索(BFS)专题-详解429. N叉树的层序遍历(N-ary Tree Level Order Traversal)

    Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree Level Order Traversal) 给定一个 N 叉树,返回其节点值的层序遍历. (即从左到右 ...

  4. BFS和DFS详解以及java实现(转载)

    作者:Leo-Yang 原文都先发布在作者个人博客:http://www.leoyang.net/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连 ...

  5. BFS详解

    广度优先搜索详解          1. 也称宽度优先搜索,顾名思义,就是将一棵树一层一层往下搜.算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点.BFS是一种完备策略,即只 ...

  6. 图论中DFS与BFS的区别、用法、详解…

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  7. 图论中DFS与BFS的区别、用法、详解?

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  8. POJ 1077 Eight (BFS+康托展开)详解

    本题知识点和基本代码来自<算法竞赛 入门到进阶>(作者:罗勇军 郭卫斌) 如有问题欢迎巨巨们提出 题意:八数码问题是在一个3*3的棋盘上放置编号为1~8的方块,其中有一块为控制,与空格相邻 ...

  9. 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS)

    参考网址:图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) - 51CTO.COM 深度优先遍历(Depth First Search, 简称 DFS) 与广度优先遍历(Breath ...

随机推荐

  1. 使用json文件给es中导入数据

    使用json文件可以给es中导入数据,10万条左右的数据可以一次导入,数量太大时导入就会报错.大数量的到导入还是需要用bulk方式. accounts.json文件格式如下: {"index ...

  2. [SCOI2010]幸运数字 [容斥原理 dfs]

    题意:"幸运号码"是十进制表示中只包含数字6和8的那些号码,求\([l,r]:r \le 10^10\)之间"幸运号码"的倍数个数 发现幸运号码貌似很少唉,去掉 ...

  3. BZOJ 3620: 似乎在梦中见过的样子 [KMP 暴力]

    和我签订契约,成为魔法少女吧 题意:求所有形似于A+B+A 的子串的数量 , 且len(A)>=k,len(B)>=1 位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一 ...

  4. 数据提交成功后如何避免alert被window.location.reload()影响

    数据提交成功用alert提示,但页面立马就重载了 alert("提交成功!"); window.location.reload(); 如何避免? 方法一: setTimeout 延 ...

  5. 二维码开源库ZBar-MDK STM32F429移植

    前两篇文章已经实现ZBar在Windows平台下的编译和使用,本文将介绍如何把ZBar移植到STM32F429,IDE使用MDK. 1. MDK工程设置 (1)不勾选Use MicroLIB ,使用I ...

  6. mysql必知必会

    春节放假没事,找了本电子书mysql必知必会敲了下.用的工具是有道笔记的markdown文档类型. 下面是根据大纲已经敲完的章节,可复制到有道笔记的查看,更美观. # 第一章 了解SQL## 什么是S ...

  7. 一步一步配置ABP Core Template with Angular

    1.首先去https://aspnetboilerplate.com/Templates下载模板工程,按如下勾选 2.下载后打开工程如下图,并设置Web.host 作为启动项目,rebuild 还原n ...

  8. MySQL数据库基础

    MySQL数据库基础 本文的所有操作是基于CMD环境,MySQL通过在命令行中输入SQL语句对数据库进行操作.配置问题可参考<打通MySQL的操作权限>中的内容,该文算是针对前期的环境配置 ...

  9. iOS实现微信外部H5支付完成后返回原APP

    看到微信最近放开了微信H5支付,公司决定把H5集成到多款APP上.下面记录下了开发过程. 由于是微信新推出的支付方式,在网上搜索到的相关资料并不多,其中有一篇文件(点此跳转)对我的整个开发过程起到了很 ...

  10. Java经典编程题50道之三十七

    有n个人围成一圈,顺序排号.从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位. public class Example37 { public static v ...