ACM之八数码问题----BFS搜索----数独游戏的模拟(上)
2013-03-24 19:51
337 查看
题目描述;数独游戏的内核模拟
八数码问题;
编号为1到8的8个正方形滑块被摆成3行3列;(有一个格子留空);
每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中;
而它原来的位置就成为了新的空格;给定初始局面和目标局面(用0表示空格);
你的任务死计算出最少的移动步数;和移动过程;如果无法到达目标局面,则输出-1;
这个问题也是要分步骤实现的,自然也涉及到状态的问题,和我的前一篇博客一样,使用的是广度优先遍历
这样可以找到最少的步数;众所周知的是BFS算法之于树和之于图是不太一样的,
因为树一旦往下走便不必担心访问到已经访问过的结点,而图呢由于有环的存在,所以会回到之前访问过的状态;
这样就需要我们写一个判断是否重复的方法,上一篇博客里面的情况比较简单,因为可以直接用状态做下标进行随机访问;
这里的情况就不一样了;我们先用c语言的遍历来实现一下,代码如下;
使用头文件string.h因为这里要用到memcmp和memcpy函数和memset;
这两个函数比我们写的循环效率要高
为什么数组选择这么大呢?排列数9!;
这里我把所有的变量都声明成全局变量的,在c语言编程方面不是一个好的编程style;
但是在ACM这种对数据量要求极大的,情况下,数组申请在全局变量比在栈中申请要好;
另外也方便了函数之间数据的交互,不需要多写什么参数了,
最后如你所见,我们的这个程序读取输入之后似乎没什么反应,其实它还是在工作的,我也是等了30多分钟之后才看到了曙光;
显然这种遍历判断是否访问过的想法不仅没有提高效率,反而增加了上万次的无辜操作;
那么该怎么提高效率呢,在下一个博客里面,我会用c++的stl库试一下;
八数码问题;
编号为1到8的8个正方形滑块被摆成3行3列;(有一个格子留空);
每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中;
而它原来的位置就成为了新的空格;给定初始局面和目标局面(用0表示空格);
你的任务死计算出最少的移动步数;和移动过程;如果无法到达目标局面,则输出-1;
2 | 6 | 4 |
1 | 3 | 7 |
5 | 8 |
8 | 1 | 2 |
7 | 3 | 6 |
4 | 2 |
这样可以找到最少的步数;众所周知的是BFS算法之于树和之于图是不太一样的,
因为树一旦往下走便不必担心访问到已经访问过的结点,而图呢由于有环的存在,所以会回到之前访问过的状态;
这样就需要我们写一个判断是否重复的方法,上一篇博客里面的情况比较简单,因为可以直接用状态做下标进行随机访问;
这里的情况就不一样了;我们先用c语言的遍历来实现一下,代码如下;
使用头文件string.h因为这里要用到memcmp和memcpy函数和memset;
这两个函数比我们写的循环效率要高
为什么数组选择这么大呢?排列数9!;
这里我把所有的变量都声明成全局变量的,在c语言编程方面不是一个好的编程style;
但是在ACM这种对数据量要求极大的,情况下,数组申请在全局变量比在栈中申请要好;
另外也方便了函数之间数据的交互,不需要多写什么参数了,
#include <stdio.h> #include <stdlib.h> #include <string.h #define MAX 1000000 typedef struct Node { int state[9];//存放本状态各个位置的数码值; int fa;//记录父节点的下标; int deepth; int last_x; int last_y; }Node; Node q[MAX];//构成状态数组; typedef struct Vis { int sequeue[9];//记录9个数码的位置; int visited; }Vis; Vis vis[MAX];//判断是否访问过; int vis_cur=0;//记录vis数组的当前索引位置; const int dx[4]={-1,1,0,0};//左右上下; const int dy[4]={0,0,-1,1}; //bool has_vis(const int * state_to_decide); int has_vis=0; int bfs();//广度优先找到目标状态; void print_path(int founded);//根据fa成员,通过递归技术实现状态依次输出; Node destination;//存储目标状态; int i,j,k; int main() { /*首先输入起始状态和目标状态*/ memset(q,0,sizeof q); for(i=0;i<9;i++) { scanf("%d",&(q[0].state[i])); } for(i=0;i<9;i++) { scanf("%d",&destination.state[i]); } memset(vis,0,sizeof vis); /*然后进行搜索并输出*/ int founded=bfs(); if(founded) print_path(founded); else printf("-1\n"); system("pause"); return 0; } int bfs() { memcpy(vis[0].sequeue,q[0].state,sizeof q[0].state); int front=0,rear=1;//用来模拟队列的先进先出,达到广度优先的目的; vis[0].visited=1;//第一个结点访问; vis_cur++; while (front<rear) { Node &first=q[front]; if (memcmp(first.state,destination.state,sizeof destination.state)==0) {//找到了目标状态; return front; } for(i=0;i<9;i++) if (!first.state[i]) {//找到空格处; break; } for(j=0;j<4;j++) {//向四个方向进行转换; Node &new_Node=q[rear]; memcpy(new_Node.state,first.state,sizeof first.state); int new_x=i%3+1+dx[j]; int new_y=i/3+1+dy[j]; if (new_x>0&&new_y>0&&new_x<4&&new_y<4) { //位置合法 new_Node.state[i]=new_Node.state[i+dx[j]+3*dy[j]];//空格位置; new_Node.state[i+dx[j]+3*dy[j]]=0;//新的状态形成了; has_vis=0; for(k=0;k<vis_cur;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的; { if((memcmp(vis[k].sequeue,new_Node.state,sizeof vis[k].sequeue))==0) { has_vis=1; break; } } if(!has_vis)//没有被访问; { new_Node.fa=front; new_Node.deepth=first.deepth+1; new_Node.last_x=dx[j]; new_Node.last_y=dy[j]; memcpy(vis[vis_cur].sequeue,new_Node.state,sizeof new_Node.state); vis[vis_cur].visited=1; vis_cur++; rear++; }//if }//if }//for front++; printf("%d %d\n",front,q[front].deepth); }//while return 0; } void print_path(int founded) { if(q[founded].fa!=founded) { print_path(q[founded].fa); } for(i=0;i<3;i++) { for(j=0;j<3;j++) { printf("%d ",q[founded].state[3*i+j]); } printf("\n"); } printf("\n"); } /*bool has_vis(const int * state_to_decide) { for(k=0;k<vis_cur;k++)//这里不用i,j因为i,j是全局变量且本函数是在循环里面的; { if(memcmp(vis[k].sequeue,state_to_decide,sizeof vis[k].sequeue)==0) return true; } return false; }*/
最后如你所见,我们的这个程序读取输入之后似乎没什么反应,其实它还是在工作的,我也是等了30多分钟之后才看到了曙光;
显然这种遍历判断是否访问过的想法不仅没有提高效率,反而增加了上万次的无辜操作;
那么该怎么提高效率呢,在下一个博客里面,我会用c++的stl库试一下;
相关文章推荐
- ACM之八数码问题----BFS搜索----数独游戏的模拟(中)
- ACM之八数码问题----BFS搜索----数独游戏的模拟(下)
- ACM之八数码问题----BFS搜索----数独游戏的模拟(上)
- ACM之八数码问题----BFS搜索----数独游戏的模拟(中)
- ACM之八数码问题----BFS搜索----数独游戏的模拟(下)
- 图算法_普通广度优先搜索(BFS)解八数码问题_C语言
- 搜索 ( 八数码问题详解:BFS,A*,IDA* )——Eight ( POJ 1077 )
- 蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)
- 八数码问题 经典搜索 bfs
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
- hdu 1043 八数码 经典搜索问题 BFS+MAP
- 单向搜索bfs,PKU1077,八数码问题
- poj 1077 Eight(经典八数码问题:bfs/Dbfs)
- BFS 八数码问题 typedef int State[9]; (BFS A*算法与优先队列)
- 简单的八数码问题(BFS)
- hdu1043 经典的八数码问题 逆向bfs打表 + 逆序数
- 最短加法链问题,POJ2248,BFS,搜索
- poj 1077 Eight 八数码问题( 康拓展开+BFS状态压缩)
- 迷宫问题(广度优先搜索BFS)
- 51nod 1185 威佐夫游戏 V2 (用乘法模拟解决大数精度问题)