POJ1077(经典的八数码问题)
2012-08-05 11:00
441 查看
很经典的八数码问题,可以用单向广度优先搜索、双向广度优先搜索、A*算法、IDA算法解。
用了双向广度优先搜索和A*算法解,在用A*算法时,纠结了好几天,后来在网上看了一份博客才发现自己错在哪。之后解出来了。虽然做这题时很纠结,不过收获真的很大,痛而快乐着…………
下面贴出用双向广度优先搜索和A*算法做的代码
//A*算法
用了双向广度优先搜索和A*算法解,在用A*算法时,纠结了好几天,后来在网上看了一份博客才发现自己错在哪。之后解出来了。虽然做这题时很纠结,不过收获真的很大,痛而快乐着…………
下面贴出用双向广度优先搜索和A*算法做的代码
//A*算法
#include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int maxn=362882; int n1,n2; //n1记录正向搜索的步骤数,n2记录逆向搜索的步骤数 int num[10]; int visit1[maxn],visit2[maxn]; //正向搜索的访问数组,逆向搜索的访问数组 int dir[4][2]={{1,0},{-1,0},{0,-1},{0,1}}; char dir1[4]={'d','u','l','r'}; char dir2[4]={'u','d','r','l'}; struct node //棋盘状态结点 { int x; int y; int step; //到达该状态走了多少步 char map[3][3]; }s,e; struct path //路径 { int dir; //到该步的方向 int pre; //该步的前一步 }path1[maxn],path2[maxn]; //正向搜索路径,逆向搜索路径 void swap(int &a,int &b) { int temp; temp=a; a=b; b=temp; } bool check(int x,int y) { if(x>=0 && x<3 && y>=0 &&y<3) return true; else return false; } void Init() { int i,j; char ch; n1=0; n2=0; num[0]=1; for(i=1;i<=9;i++) num[i]=num[i-1]*i; e.x=2; //最终状态的坐标值 e.y=2; for(i=0;i<3;i++) //初始化棋盘上的各个格子的值 for(j=0;j<3;j++) e.map[i][j]=i*3+j+1+'0'; for(i=0;i<3;i++) for(j=0;j<3;j++) { cin>>ch; if(ch=='x') { s.map[i][j]='9'; s.x=i; s.y=j; } else s.map[i][j]=ch; } } int calculate(char m[][3]) //计算所处的状态 { int i,j,a,b,v,count,temp; v=0; for(i=0;i<9;i++) { count=0; a=m[i/3][i%3]-48; for(j=i+1;j<9;j++) { b=m[j/3][j%3]-48; if(a>b) count++; } v+=count*num[a-1]; } return v; } bool TBFS() { int i,x,y,th,temp; queue<node> L,R; node point; s.step=0; e.step=0; L.push(s); R.push(e); visit1[calculate(s.map)]=1; visit2[calculate(e.map)]=1; while(!L.empty() || !R.empty()) { if(!L.empty()) { point=L.front(); L.pop(); temp=point.step; //暂时存储该状态是第几状态,及所用的步骤数 for(i=0;i<4;i++) { x=point.x+dir[i][0]; y=point.y+dir[i][1]; if(check(x,y)) { swap(point.map[x][y],point.map[point.x][point.y]); swap(x,point.x); swap(y,point.y); th=calculate(point.map); if(visit2) //逆向搜索已经访问了该状态,访问交叉,结束搜索 { //搜索中的每一步都对应棋盘的一个状态 path1[++n1].pre=temp; //正向搜索路径上到达该步懂得前一步即为temp path1[n1].dir=i; n2=visit2 -1; //逆向搜索的总步数减少一,因为正向搜索的步骤数加了一 return true; } if(!visit1 ) { point.step=++n1; path1[n1].pre=temp; path1[n1].dir=i; visit1 =n1+1; //编号为th的状态是正向搜索第n1+1步访问的,状态编号从一开始,即厨师和最终的状态都记一,步骤数从0开始 L.push(point); } swap(x,point.x); swap(y,point.y); swap(point.map[x][y],point.map[point.x][point.y]); } } } if(!R.empty()) { point=R.front(); R.pop(); temp=point.step; for(i=0;i<4;i++) { x=point.x+dir[i][0]; y=point.y+dir[i][1]; if(check(x,y)) { swap(point.map[x][y],point.map[point.x][point.y]); swap(x,point.x); swap(y,point.y); th=calculate(point.map); if(visit1 ) //正向已经搜索了该状态,搜索交叉,搜索结束 { path2[++n2].pre=temp; path2[n2].dir=i; n1=visit1 -1; return true; } if(!visit2 ) { point.step=++n2; path2[n2].pre=temp; path2[n2].dir=i; visit2 =n2+1; R.push(point); } swap(x,point.x); swap(y,point.y); swap(point.map[x][y],point.map[point.x][point.y]); } } } } return false; } int main() { int i,k; int d[maxn]; Init(); if(calculate(s.map)==calculate(e.map)); else if(TBFS()) { k=0; while(n1>0) { d[k++]=path1[n1].dir; n1=path1[n1].pre; } for(i=k-1;i>=0;i--) printf("%c",dir1[d[i]]); while(n2>0) { printf("%c",dir2[path2[n2].dir]); n2=path2[n2].pre; } printf("\n"); } else printf("unsolvable\n"); return 0; }
//双向广度优先搜索#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int maxn=362882; int st,end,pre[maxn],a[10]; char path[maxn]; //路径 bool visit[maxn]; //标志访问数组 int frac[9]={1,1,2,6,24,120,720,5040,40320}; struct node { int map[10]; int state; int x; int g; int f; bool operator <(const node&a)const { return f>a.f; //在优先队列中,f较小的优先出队 } }; int hash(int s[]) //计算所处的状态 { int i,j,v,count; v=0; for(i=1;i<=9;i++) { count=0; for(j=1;j<i;j++) if(s[j]>s[i]) count++; v+=count*frac[i-1]; } return v; } int geth(int s[]) //计算启发函数值,即曼哈顿距离 { int i,a,b,c,d,v; v=0; for(i=1;i<=9;i++) { if(s[i]==9) continue; a=(i+2)/3; //原来位置的x b=(i-1)%3+1; //原来位置的y c=(s[i]+2)/3; d=(s[i]-1)%3+1; v+=abs(a-c)+abs(b-d); } return v; } void Astar() { int i,th; priority_queue<node> q; node point1,point2; point1.state=hash(a); st=point1.state; visit[st]=true; if(st==end) return ; point1.g=0; //搜索的深度 point1.f=geth(a); for(i=1;i<=9;i++) { point1.map[i]=a[i]; if(a[i]==9) point1.x=i; } q.push(point1); while(!q.empty()) { point1=q.top(); q.pop(); if((point1.x+2)/3!=1) //向上交换数字 { point2=point1; point2.x=point1.x-3; point2.map[point1.x]=point2.map[point2.x]; point2.map[point2.x]=9; th=hash(point2.map); if(!visit) { point2.g++; point2.f=point2.g+geth(point2.map); point2.state=th; pre =point1.state; path ='u'; visit =true; if(th==end) return ; q.push(point2); } } if((point1.x+2)/3!=3) //向下交换 { point2=point1; point2.x=point1.x+3; point2.map[point1.x]=point2.map[point2.x]; point2.map[point2.x]=9; th=hash(point2.map); if(!visit ) { point2.g++; point2.f=point2.g+geth(point2.map); point2.state=th; pre =point1.state; path ='d'; visit =true; if(th==end) return ; q.push(point2); } } if(point1.x%3!=1) //向左交换数字 { point2=point1; point2.x=point1.x-1; point2.map[point1.x]=point2.map[point2.x]; point2.map[point2.x]=9; th=hash(point2.map); if(!visit ) { point2.g++; point2.f=point2.g+geth(point2.map); point2.state=th; pre =point1.state; path ='l'; visit =true; if(th==end) return ; q.push(point2); } } if(point1.x%3!=0) //向右交换数字 { point2=point1; point2.x=point1.x+1; point2.map[point1.x]=point2.map[point2.x]; point2.map[point2.x]=9; th=hash(point2.map); if(!visit ) { point2.g++; point2.f=point2.g+geth(point2.map); point2.state=th; pre =point1.state; path ='r'; visit =true; if(th==end) return ; q.push(point2); } } } } int main() { int i,j,k; char str[50]; gets(str); k=0; for(i=0;str[i];i++) { if(str[i]=='x') a[++k]=9; else if(str[i]!=' ') a[++k]=str[i]-'0'; } end=0; memset(visit,0,sizeof(visit)); Astar(); j=0; while(st!=end) { str[j++]=path[end]; end=pre[end]; } for(i=j-1;i>=0;i--) printf("%c",str[i]); printf("\n"); return 0; } 相关文章推荐
- HDU 1043 Eight(经典八数码问题)对比POJ 1077
- poj 1077 Eight(经典八数码问题:bfs/Dbfs)
- hdu 1043 /poj 1077 Eight(经典八数码问题,BFS+康托展开)
- POJ 1077 八数码问题 练习搜索
- pku 1077 Eight 经典8数码问题 单向BFS + A* BFS + 双向BFS
- POJ 1077 Eight 八数码问题 BFS
- poj 1077 Eight A*解八数码问题
- POJ 1077 Eight(bfs八数码问题)
- 八数码问题 IDA*算法+曼哈顿距离 poj 1077
- 搜索 ( 八数码问题详解:BFS,A*,IDA* )——Eight ( POJ 1077 )
- IDA* 解八数码问题: POJ 1077
- Poj 1077 Eight 八数码问题 (搜索)
- 【hdu1043 && poj 1077】八数码问题
- hdu 1034 & poj 1077 Eight 传说中的八数码问题。真是一道神题,A*算法+康托展开
- hdu 1034 & poj 1077 Eight 传说中的八数码问题。真是一道神题,A*算法+康托展开
- 双向BFS解八数码问题: POJ 1077
- bfs+hash poj 1077/hdu 1043 八数码问题
- Poj 1077 eight(BFS+全序列Hash解八数码问题)
- poj 1077--Eight(八数码问题,BFS,A*,全排列的哈希)
- POJ 1077 Eight A*算法 八数码问题