八数码八境界代码
Posted mhp的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了八数码八境界代码相关的知识,希望对你有一定的参考价值。
本文转自:http://www.cnblogs.com/zufezzt/p/5659276.html
判断无解的情况(写完七种境界才发现有直接判断无解的方法):
一个状态表示成一维的形式,求出除0之外所有数字的逆序数之和,也就是每个数字前面比它大的数字的个数的和,称为这个状态的逆序。
若两个状态的逆序奇偶性相同,则可相互到达,否则不可相互到达。
POJ提交记录(从下往上依次为第1,2,3,4,5,6,7,8境界):
本文转自:http://www.cnblogs.com/zufezzt/p/5659276.html
HDU提交记录(从下往上依次为第1,2,3,4,5,6,7,8境界):
PS:因为HDU是多组测试数据,所以一般POJ上要100ms以上才能AC的方法,在HDU上是无法通过的(境界3除外)。
境界一、 暴力广搜+STL (HDU 内存超限,POJ 时间超限)
map存路径,set判重,string存状态,毫无疑问,炸了。
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> #include<set> #include<map> #include<algorithm> #include<iostream> using namespace std; char input[1000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "durl"; set<string>f; map<string, string>m; int sz = 0; struct node { string s; string path; int pos; node() {} node(string str, string pa, int Pos) { s = str; path = pa; pos = Pos; } }; bool g(int a, int b) { if (a >= 0 && a <= 2 && b >= 0 && b <= 2) return 1; return 0; } void pre() { queue<node>q; q.push(node("12345678x", "", 8)); m["12345678x"] = ""; f.insert("12345678x"); while (!q.empty()) { node h = q.front(); q.pop(); int a = h.pos / 3, b = h.pos % 3; for (int i = 0; i<4; i++) { int x = a + dir[i][0], y = b + dir[i][1]; if (!g(x, y)) continue; int pos = 3 * x + y; swap(h.s[h.pos], h.s[pos]); if (f.find(h.s) != f.end()) { swap(h.s[h.pos], h.s[pos]); continue; } q.push(node(h.s, d[i] + h.path, pos)); f.insert(h.s); m[h.s] = d[i] + h.path; swap(h.s[h.pos], h.s[pos]); } } } int main() { pre(); while(~scanf("%s",input)) { string v=""; v = v + input[0]; for (int i = 1; i <= 8; i++) { scanf("%s", input); v = v + input[0]; } if (m[v] == "") cout << "unsolvable" << endl; else cout << m[v] << endl; } return 0; }
境界二、广搜+哈希(POJ 453ms)
利用康托展开对状态进行hash,hash值对应0--(9!-1),因此可以开数组判重,路径的记录可以记录到达某状态的最后一步操作是什么与父节点是什么。
从输入的状态开始进行BFS,直到找到最终状态。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<queue> #include<stack> #include<algorithm> using namespace std; char t[1000]; int c[10]; int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; char path[10]={\'u\',\'d\',\'l\',\'r\'}; char op[5],input[20]; int ans; stack<int>S; struct Node { int s,p; Node(){} Node(int S,int P){s=S,p=P;} }; struct Path { int from,dir; }pa[400000]; bool f[400000]; int getnum() { int res=0; for(int i=0;t[i];i++) for(int j=i+1;t[j];j++) if(t[j]<t[i]) res=res+c[8-i]; return res; } void getstr(int val) { int tmp[10],flag[10]; memset(flag,0,sizeof flag); for(int i=0;i<9;i++) tmp[i]=val/c[8-i],val=val%c[8-i]; for(int i=0;i<9;i++) { int num=0; for(int j=0;j<9;j++) { if(flag[j]==0) num++; if(num==tmp[i]+1) { t[i]=j+\'0\'+1; if(t[i]==\'9\') t[i]=\'x\'; flag[j]=1;break; } } } } void bfs(int val,int Pos) { queue<Node>Q; Q.push(Node(val,Pos)); f[val]=1; pa[val].from=-1,pa[val].dir=-1; while(!Q.empty()) { Node h=Q.front(); Q.pop(); if(h.s==0) { ans=1; int now=h.s; while(1) { if(pa[now].from==-1) break; S.push(pa[now].dir); now=pa[now].from; } break; } int a=h.p/3, b=h.p%3; getstr(h.s); for(int i=0;i<4;i++) { int x=a+dir[i][0],y=b+dir[i][1]; if(!(x>=0&&x<=2&&y>=0&&y<=2)) continue; int newpos=3*x+y; swap(t[newpos],t[h.p]); int news=getnum(); if(f[news]) {swap(t[newpos],t[h.p]);continue;} pa[news].from=h.s, pa[news].dir=i, f[news]=1; Q.push(Node(news,newpos)); swap(t[newpos],t[h.p]); } } } int main() { c[0]=1; for(int i=1;i<=8;i++) c[i]=c[i-1]*i; while(~scanf("%s",op)) { t[0]=op[0]; int pos; for(int i=1;i<=8;i++) { scanf("%s",op); t[i]=op[0]; if(t[i]==\'x\') pos=i; } int state=getnum(); int sum=0; for(int i=0;t[i];i++) { if(t[i]==\'x\') continue; for(int j=0;j<i;j++) { if(t[j]==\'x\') continue; if(t[i]<t[j]) sum++; } } if(sum%2==1) { printf("unsolvable\\n"); continue; } ans=0; memset(f,0,sizeof f); bfs(state,pos); while(!S.empty()) { printf("%c",path[S.top()]); S.pop(); } printf("\\n"); } return 0; }
境界三、广搜+哈希+打表(HDU 263ms,POJ 579ms)
从最终状态(0)开始进行BFS。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<queue> #include<stack> #include<algorithm> using namespace std; char t[1000]; int c[10]; int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; char path[10]={\'d\',\'u\',\'r\',\'l\'}; char op[5],input[20]; struct Node { int s,p; Node(){} Node(int S,int P){s=S,p=P;} }; struct Path { int from,dir; }pa[400000]; bool f[400000]; int getnum() { int res=0; for(int i=0;t[i];i++) for(int j=i+1;t[j];j++) if(t[j]<t[i]) res=res+c[8-i]; return res; } void getstr(int val) { int tmp[10],flag[10]; memset(flag,0,sizeof flag); for(int i=0;i<9;i++) tmp[i]=val/c[8-i],val=val%c[8-i]; for(int i=0;i<9;i++) { int num=0; for(int j=0;j<9;j++) { if(flag[j]==0) num++; if(num==tmp[i]+1) { t[i]=j+\'0\'+1; if(t[i]==\'9\') t[i]=\'x\'; flag[j]=1;break; } } } } void pre() { queue<Node>Q; Q.push(Node(0,8)); f[0]=1; pa[0].from=-1,pa[0].dir=-1; while(!Q.empty()) { Node h=Q.front(); Q.pop(); int a=h.p/3, b=h.p%3; getstr(h.s); for(int i=0;i<4;i++) { int x=a+dir[i][0],y=b+dir[i][1]; if(!(x>=0&&x<=2&&y>=0&&y<=2)) continue; int newpos=3*x+y; swap(t[newpos],t[h.p]); int news=getnum(); if(f[news]) {swap(t[newpos],t[h.p]);continue;} pa[news].from=h.s, pa[news].dir=i, f[news]=1; Q.push(Node(news,newpos)); swap(t[newpos],t[h.p]); } } } int main() { c[0]=1; for(int i=1;i<=8;i++) c[i]=c[i-1]*i; pre(); while(~scanf("%s",op)) { t[0]=op[0]; for(int i=1;i<=8;i++) {scanf("%s",op); t[i]=op[0];} int state=getnum(); if(f[state]==0) printf("unsolvable\\n"); else { while(1) { if(pa[state].from==-1) break; printf("%c",path[pa[state].dir]); state=pa[state].from; } printf("\\n"); } } return 0; }
境界四、双向广搜+哈希(HDU 2636ms, POJ 32ms)
从起点和终点同时开始搜,当某个状态被两个方向的搜索同时搜过时,搜索结束,输出路径。
HDU 不加无解判断剪枝会超时。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; char input[1000],t[1000],op[5]; int c[10]; struct Node { int s,p; Node(){} Node(int S,int P){s=S,p=P;} }; struct Path { int from,dir; }path[400000]; int f[400000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d[3] = {"","udlr","durl"}; queue<Node>q[3]; int ans; stack<int>S; queue<int>Q; int getnum() { int res=0; for(int i=0;t[i];i++) for(int j=i+1;t[j];j++) if(t[j]<t[i]) res=res+c[8-i]; return res; } void getstr(int val) { int tmp[10],flag[10]; memset(flag,0,sizeof flag); for(int i=0;i<9;i++) tmp[i]=val/c[8-i],val=val%c[8-i]; for(int i=0;i<9;i++) { int num=0; for(int j=0;j<9;j++) { if(flag[j]==0) num++; if(num==tmp[i]+1) { t[i]=j+\'0\'+1; if(t[i]==\'9\') t[i]=\'x\'; flag[j]=1;break; } } } } bool g(int a, int b) { if (a >= 0 && a <= 2 && b >= 0 && b <= 2) return 1; return 0; } void bfs(int now) { Node h=q[now].front(); q[now].pop(); int a=h.p/3,b=h.p%3; getstr(h.s); for(int i=0;i<4;i++) { int x=a+dir[i][0],y=b+dir[i][1]; if(!g(x,y)) continue; int pos = 3 * x + y; swap(t[h.p],t[pos]); if(f[getnum()]==now) { swap(t[h.p],t[pos]); continue; } else if(f[getnum()]!=0) { ans=1; if(now==1) { S.push(i); int u=h.s; while(path[u].from!=-1) { S.push(path[u].dir); u=path[u].from; } u=getnum(); while(path[u].from!=-1) { Q.push(path[u].dir); u=path[u].from; } } else { Q.push(i); int u=h.s; while(path[u].from!=-1) { Q.push(path[u].dir); u=path[u].from; } u=getnum(); while(path[u].from!=-1) { S.push(path[u].dir); u=path[u].from; } } break; } else { f[getnum()]=now; path[getnum()].from=h.s; path[getnum()].dir=i; q[now].push(Node(getnum(),pos)); swap(t[h.p],t[pos]); } } } void read() { t[0]=op[0]; for(int i=1;i<=8;i++) {scanf("%s",op); t[i]=op[0];} for(int i=0;i<=9;i++) input[i]=t[i]; } void init() { memset(f,ans=0,sizeof f); while(!q[1].empty()) q[1].pop(); while(!q[2].empty()) q[2].pop(); } void work(int s,int pos) { q[1].push(Node(s,pos)); q[2].push(Node(0,8)); f[s]=1; path[s].from=path[s].dir=-1; f[0]=2; path[0].from=path[0].dir=-1; while((!q[1].empty())&&(!q[2].empty())) { if(ans==1) break; bfs(1); if(ans==1) break; bfs(2); if(ans==1) break; } } int main() { c[0]=1; for(int i=1;i<=8;i++) c[i]=c[i-1]*i; while(~scanf("%s",op)) { read(); int sum=0; for(int i=0;t[i];i++) { if(t[i]==\'x\') continue; for(int j=0;j<i;j++) { if(t[j]==\'x\') continue; if(t[i]<t[j]) sum++; } } if(sum%2==1) { printf("unsolvable\\n"); continue; } init(); for(int i=0;i<9;i++) if(input[i]==\'x\'){work(getnum(),i); break; } if(ans==1) { while(!S.empty()) { printf("%c",d[1][S.top()]); S.pop(); } while(!Q.empty()) { printf("%c",d[2][Q.front()]); Q.pop(); } } else printf("unsolvable"); printf("\\n"); } return 0; }
境界五、A*+哈希+简单估价函数(POJ 391ms)
之后的境界采用最小堆优化,这里我直接用了,f小的先取
试了一下用普通队列的,G++跑了680ms左右,C++TLE(主要原因是写法不好,我常数写的有点大了)。显然最小堆优化在效率上有极大的提高。
g(n)是深度,即从初
以上是关于八数码八境界代码的主要内容,如果未能解决你的问题,请参考以下文章
求八数码问题算法,并说明下该算法优缺点,要算法,不是源代码(可以没有)。