八数码问题实现(裸BFS版+A*版)C++实现
2017-03-22 11:51
267 查看
八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
所谓问题的一个状态就是棋子在棋盘上的一种摆法。棋子移动后,状态就会发生改变。解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。
人工智能课的作业。感觉一点都不智能。。
算法核心是bfs hash用的是康拓展开
输入是第一行是初始状态,第二行是终止状态,空格用0表示。
012
345 ———> 012345678
678
一些测试数据:
012345678
102345678
103425678
123405678
123045678
123405678
123475608
123405678
123450678
123405678
234150768
123456780
结果:
最少步数为:1
路径为:r
最少步数为:1
路径为:d
最少步数为:1
路径为:r
最少步数为:1
路径为:u
最少步数为:1
路径为:l
最少步数为:19
路径为:ullddrurdllurdruldr
下面贴两个版本的代码
裸BFS版
参考kuangbin的HDU1043的代码写的,因为自己原先写了一个觉得很丑,还是大佬的姿势比较优美。
A*版
h(x)用的是到当前状态的步数
g(x)是用的当前每个格子中的数到最终位置的曼哈顿距离(街区距离)的和,然后优先队列维护一下就好了。
所谓问题的一个状态就是棋子在棋盘上的一种摆法。棋子移动后,状态就会发生改变。解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。
人工智能课的作业。感觉一点都不智能。。
算法核心是bfs hash用的是康拓展开
输入是第一行是初始状态,第二行是终止状态,空格用0表示。
012
345 ———> 012345678
678
一些测试数据:
012345678
102345678
103425678
123405678
123045678
123405678
123475608
123405678
123450678
123405678
234150768
123456780
结果:
最少步数为:1
路径为:r
最少步数为:1
路径为:d
最少步数为:1
路径为:r
最少步数为:1
路径为:u
最少步数为:1
路径为:l
最少步数为:19
路径为:ullddrurdllurdruldr
下面贴两个版本的代码
裸BFS版
参考kuangbin的HDU1043的代码写的,因为自己原先写了一个觉得很丑,还是大佬的姿势比较优美。
#include "cstdio" #include "queue" #include "cstring" #include "string.h" #include "iostream" #include "algorithm" #include "cmath" #include "vector" using namespace std; const int MAXN=1000000; int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重 // 0!1!2!3! 4! 5! 6! 7! 8! 9! bool vis[MAXN];//标记 string path; int aim;//123456780对应的康拖展开的hash值 int aimmap[3][3]; int mymove[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r char indexs[5]="udlr";//正向搜索 int cantor(int s[])//康拖展开求该序列的hash值 { int sum=0; for(int i=0;i<9;i++) { int num=0; for(int j=i+1;j<9;j++) if(s[j]<s[i])num++; sum+=(num*fac[9-i-1]); } return sum+1; } struct Node { int s[9]; int loc;//“0”的位置 int status;//康拖展开的hash值 int step;//统计步数 也用作gx int hx; string path;//路径 void gethx() { int temp=0; for(int i=0;i<9;i++) { int cur_x=i/3; int cur_y=i%3; for(int j=0;j<3;j++) { for(int k=0;k<3;k++) { if(aimmap[j][k]==s[i]) { temp+=abs(j-cur_x)+abs(k-cur_y); } } } } hx=temp; } }; struct cmp //优先队列需要的排序函数,升序 { bool operator()(Node &a,Node &b) { int aa=a.hx+a.step; int bb=b.hx+b.step; return aa>bb; } }; Node ncur; bool bfs() { memset(vis,false,sizeof(vis)); Node cur,next; priority_queue<Node,vector<Node>,cmp>q; ncur.gethx(); q.push(ncur); while(!q.empty()) { cur=q.top(); q.pop(); if(cur.status==aim) { path=cur.path; return true; } int x=cur.loc/3; int y=cur.loc%3; for(int i=0;i<4;i++) { int tx=x+mymove[i][0]; int ty=y+mymove[i][1]; if(tx<0||tx>2||ty<0||ty>2)continue; next=cur; next.loc=tx*3+ty; next.s[cur.loc]=next.s[next.loc]; next.s[next.loc]=0; next.status=cantor(next.s); if(!vis[next.status]) { next.step++; ncur.gethx(); vis[next.status]=true; next.path=next.path+indexs[i]; if(next.status==aim) { cout<<"最少步数为:"<<next.step<<endl; path=next.path; return true; } q.push(next); next.step--; } } } return false; } int main() { char start; int myaim[9]; while(1) { ncur.step=0; for(int i=0;i<9;i++) { cin>>start; if(start=='0') ncur.loc=i; ncur.s[i]=start-'0'; } ncur.status=cantor(ncur.s); for(int i=0;i<9;i++) { char to; cin>>to; myaim[i]=to-'0'; int cur_x=i/3; int cur_y=i%3; aimmap[cur_x][cur_y]=to-'0'; } aim=cantor(myaim); ncur.status=cantor(ncur.s); if(bfs()) { cout<<"路径为:"<<path<<endl; } else cout<<"无解"<<endl; cout<<endl<<endl; } return 0; }
A*版
h(x)用的是到当前状态的步数
g(x)是用的当前每个格子中的数到最终位置的曼哈顿距离(街区距离)的和,然后优先队列维护一下就好了。
#include "cstdio" #include "queue" #include "cstring" #include "string.h" #include "iostream" #include "algorithm" #include "cmath" #include "vector" using namespace std; const int MAXN=1000000; int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重 // 0!1!2!3! 4! 5! 6! 7! 8! 9! bool vis[MAXN];//标记 string path; int aim;//123456780对应的康拖展开的hash值 int aimmap[3][3]; int mymove[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r char indexs[5]="udlr";//正向搜索 int cantor(int s[])//康拖展开求该序列的hash值 { int sum=0; for(int i=0;i<9;i++) { int num=0; for(int j=i+1;j<9;j++) if(s[j]<s[i])num++; sum+=(num*fac[9-i-1]); } return sum+1; } struct Node { int s[9]; int loc;//“0”的位置 int status;//康拖展开的hash值 int step;//统计步数 也用作gx int hx; string path;//路径 void gethx() { int temp=0; for(int i=0;i<9;i++) { int cur_x=i/3; int cur_y=i%3; for(int j=0;j<3;j++) { for(int k=0;k<3;k++) { if(aimmap[j][k]==s[i]) { temp+=abs(j-cur_x)+abs(k-cur_y); } } } } hx=temp; } }; struct cmp //优先队列需要的排序函数,升序 { bool operator()(Node &a,Node &b) { int aa=a.hx+a.step; int bb=b.hx+b.step; return aa>bb; } }; Node ncur; bool bfs() { memset(vis,false,sizeof(vis)); Node cur,next; priority_queue<Node,vector<Node>,cmp>q; ncur.gethx(); q.push(ncur); while(!q.empty()) { cur=q.top(); q.pop(); if(cur.status==aim) { path=cur.path; return true; } int x=cur.loc/3; int y=cur.loc%3; for(int i=0;i<4;i++) { int tx=x+mymove[i][0]; int ty=y+mymove[i][1]; if(tx<0||tx>2||ty<0||ty>2)continue; next=cur; next.loc=tx*3+ty; next.s[cur.loc]=next.s[next.loc]; next.s[next.loc]=0; next.status=cantor(next.s); if(!vis[next.status]) { next.step++; ncur.gethx(); vis[next.status]=true; next.path=next.path+indexs[i]; if(next.status==aim) { cout<<"最少步数为:"<<next.step<<endl; path=next.path; return true; } q.push(next); next.step--; } } } return false; } int main() { char start; int myaim[9]; while(1) { ncur.step=0; for(int i=0;i<9;i++) { cin>>start; if(start=='0') ncur.loc=i; ncur.s[i]=start-'0'; } ncur.status=cantor(ncur.s); for(int i=0;i<9;i++) { char to; cin>>to; myaim[i]=to-'0'; int cur_x=i/3; int cur_y=i%3; aimmap[cur_x][cur_y]=to-'0'; } aim=cantor(myaim); ncur.status=cantor(ncur.s); if(bfs()) { cout<<"路径为:"<<path<<endl; } else cout<<"无解"<<endl; cout<<endl<<endl; } return 0; }
相关文章推荐
- A*算法来实现八数码的问题 C++
- 八数码问题:C++广度搜索实现
- A*算法解决八数码问题的C++实现
- 简单的用c++实现的八数码问题
- 八数码问题:C++广度搜索实现
- 八皇后问题的c++实现
- VC++编译问题汇总1 单链表的表示和实现,基于c++
- 从易到难编写C++程序,(8)问题:实现一个矩阵类
- 用c++实现的8皇后问题
- 从易到难编写C++程序,(4)问题:实现一个大整数表示的BigInt类
- 贪心算法运用于背包问题(C++实现)
- 《数据结构与算法分析-C++描述》List实现的问题,g++太符合标准,以至于有的时候虽然正确,但是却会让你吃惊
- 从易到难编写C++程序,(3)问题:实现一个复杂的猜数字游戏
- n后问题的c++实现
- 一笔画问题的c++实现
- 使用ActionScript3基于Flex实现八数码问题启发式搜索
- C/C++实现HTTP/HTTPS的POST存在的问题
- 从易到难编写C++程序,(7)问题:利用问题(6)的发牌,实现24点游戏
- 独立钻石跳棋问题的C++实现
- 约瑟夫问题C++实现