看了這篇博客的講解,挺不錯的。http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.htmlhtml
判斷無解的狀況(寫完七種境界才發現有直接判斷無解的方法):node
一個狀態表示成一維的形式,求出除0以外全部數字的逆序數之和,也就是每一個數字前面比它大的數字的個數的和,稱爲這個狀態的逆序。ios
若兩個狀態的逆序奇偶性相同,則可相互到達,不然不可相互到達。數組
POJ提交記錄(從下往上依次爲第1,2,3,4,5,6,7,8境界):ide
HDU提交記錄(從下往上依次爲第1,2,3,4,5,6,7,8境界):函數
PS:由於HDU是多組測試數據,因此通常POJ上要100ms以上才能AC的方法,在HDU上是沒法經過的(境界3除外)。測試
境界1、 暴力廣搜+STL (HDU 內存超限,POJ 時間超限)優化
map存路徑,set判重,string存狀態,毫無疑問,炸了。url
#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; }
境界2、廣搜+哈希(POJ 453ms)spa
利用康託展開對狀態進行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; }
境界3、廣搜+哈希+打表(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; }
境界4、雙向廣搜+哈希(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; }
境界5、A*+哈希+簡單估價函數(POJ 391ms)
以後的境界採用最小堆優化,這裏我直接用了,f小的先取
試了一下用普通隊列的,G++跑了680ms左右,C++TLE(主要緣由是寫法很差,我常數寫的有點大了)。顯然最小堆優化在效率上有極大的提升。
g(n)是深度,即從初始到目前的操做次數,h(n)是簡單估價函數,表示目前狀態與最終狀態同一位置不一樣數字的個數。
#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; int f,g,h; Node(){} Node(int S,int P,int G,int H) { s=S,p=P; g=G,h=H; f=g+h; } bool operator < (const Node &a) const { return f>a.f; } }; struct Path { int from,dir; }path[400000]; int flag[400000]; int G[400000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "udlr"; priority_queue<Node>Q; int ans; stack<int>S; 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 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(G,-1,sizeof G); memset(flag,0,sizeof flag); while(!Q.empty()) Q.pop(); } int H(int val) { char tmp[10]; for(int i=0;i<=9;i++) tmp[i]=t[i]; getstr(val); int res=0; for(int i=0;i<9;i++) { if(i<8) if(t[i]-'0'!=i+1) res++; if(i==8&&t[i]!='x') res++; } for(int i=0;i<=9;i++) t[i]=tmp[i]; return res; } void A_star(int s,int pos) { flag[s]=2; G[s]=0; path[s].from=-1; path[s].dir=-1; Q.push(Node(s,pos,0,H(s))); while(!Q.empty()) { Node h=Q.top(); Q.pop(); flag[h.s]=2; getstr(h.s); if(h.s==0) { ans=1; int now=h.s; while(1) { if(path[now].from==-1) return; S.push(path[now].dir); now=path[now].from; } } int a=h.p/3,b=h.p%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 newpos=3*x+y; swap(t[h.p],t[newpos]); int news=getnum(); swap(t[h.p],t[newpos]); if(flag[news]==0||(flag[news]==1&&h.g+1<G[news])) { flag[news]=1; G[news]=h.g+1; path[news].from=h.s; path[news].dir=i; Q.push(Node(news,newpos,h.g+1,H(news))); } } } } 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'){A_star(getnum(),i); break; } while(!S.empty()){printf("%c",d[S.top()]); S.pop();} printf("\n"); } return 0; }
境界6、A*+哈希+曼哈頓距離 (POJ 735ms)
與境界5惟一不一樣的是 估價函數h()。這裏估價函數採用曼哈頓距離。
#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; int f,g,h; Node(){} Node(int S,int P,int G,int H) { s=S,p=P; g=G,h=H; f=g+h; } }; struct Path { int from,dir; }path[400000]; int flag[400000]; int G[400000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "udlr"; queue<Node>Q; int ans; stack<int>S; 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 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(G,-1,sizeof G); memset(flag,0,sizeof flag); while(!Q.empty()) Q.pop(); } int H(int val) { char tmp[10]; for(int i=0;i<=9;i++) tmp[i]=t[i]; getstr(val); int res=0; for(int i=0;i<9;i++) { if(t[i]=='x') continue; int num=t[i]-'0'-1; int a=i/3,b=i%3; int x=num/3,y=num%3; res=res+abs(a-x)+abs(b-y); } for(int i=0;i<=9;i++) t[i]=tmp[i]; return res; } void A_star(int s,int pos) { flag[s]=2; G[s]=0; path[s].from=-1; path[s].dir=-1; Q.push(Node(s,pos,0,H(s))); while(!Q.empty()) { Node h=Q.front(); Q.pop(); flag[h.s]=2; getstr(h.s); if(h.s==0) { ans=1; int now=h.s; while(1) { if(path[now].from==-1) return; S.push(path[now].dir); now=path[now].from; } } int a=h.p/3,b=h.p%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 newpos=3*x+y; swap(t[h.p],t[newpos]); int news=getnum(); swap(t[h.p],t[newpos]); if(flag[news]==0||(flag[news]==1&&h.g+1<G[news])) { flag[news]=1; G[news]=h.g+1; path[news].from=h.s; path[news].dir=i; Q.push(Node(news,newpos,h.g+1,H(news))); } } } } 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'){A_star(getnum(),i); break; } while(!S.empty()){printf("%c",d[S.top()]); S.pop();} printf("\n"); } return 0; }
境界7、A*+哈希+曼哈頓距離+小頂堆 (HDU 1404ms,POJ 16ms)
境界六加上最小堆優化,這個優化的效率改進是巨大的!!!!
#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; int f,g,h; Node(){} Node(int S,int P,int G,int H) { s=S,p=P; g=G,h=H; f=g+h; } bool operator < (const Node &a) const { return f>a.f; } }; struct Path { int from,dir; }path[400000]; int flag[400000]; int G[400000]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "udlr"; priority_queue<Node>Q; int ans; stack<int>S; 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 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(G,-1,sizeof G); memset(flag,0,sizeof flag); while(!Q.empty()) Q.pop(); } int H(int val) { char tmp[10]; for(int i=0;i<=9;i++) tmp[i]=t[i]; getstr(val); int res=0; for(int i=0;i<9;i++) { if(t[i]=='x') continue; int num=t[i]-'0'-1; int a=i/3,b=i%3; int x=num/3,y=num%3; res=res+abs(a-x)+abs(b-y); } for(int i=0;i<=9;i++) t[i]=tmp[i]; return res; } void A_star(int s,int pos) { flag[s]=2; G[s]=0; path[s].from=-1; path[s].dir=-1; Q.push(Node(s,pos,0,H(s))); while(!Q.empty()) { Node h=Q.top(); Q.pop(); flag[h.s]=2; getstr(h.s); if(h.s==0) { ans=1; int now=h.s; while(1) { if(path[now].from==-1) return; S.push(path[now].dir); now=path[now].from; } } int a=h.p/3,b=h.p%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 newpos=3*x+y; swap(t[h.p],t[newpos]); int news=getnum(); swap(t[h.p],t[newpos]); if(flag[news]==0||(flag[news]==1&&h.g+1<G[news])) { flag[news]=1; G[news]=h.g+1; path[news].from=h.s; path[news].dir=i; Q.push(Node(news,newpos,h.g+1,H(news))); } } } } 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'){A_star(getnum(),i); break; } while(!S.empty()){printf("%c",d[S.top()]); S.pop();} printf("\n"); } return 0; }
境界8、IDA*+曼哈頓距離(HDU 2106ms,POJ 79ms)
採用迭代深搜的思想,利用A*估價函數剪枝。
第一次容許搜索到的深度爲limit,若是有解,直接輸出。
在最大值深度爲limit的狀況下,若是無解,則將limit++,繼續從頭開始搜索。直到搜到解。
剪枝:if(deep+h(s)>limit) return; deep表示這一次搜索達到此狀態的操做次數,h(s)爲估價函數。
IDA*策略佔用空間極小,通常狀況下效率會比A*高。
至於爲何個人IDA*比A*慢.....估計我這種寫法常數太大了吧......
#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]; int dir[4][2] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } }; string d = "udlr"; int flag,limit,length; int path[1000]; 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 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]; } int H(int val) { char tmp[10]; for(int i=0;i<=9;i++) tmp[i]=t[i]; getstr(val); int res=0; for(int i=0;i<9;i++) { if(t[i]=='x') continue; int num=t[i]-'0'-1; int a=i/3,b=i%3; int x=num/3,y=num%3; res=res+abs(a-x)+abs(b-y); } for(int i=0;i<=9;i++) t[i]=tmp[i]; return res; } void dfs(int pos,int s,int deep,int pre_dir) { if(s==0) { length=deep; flag=1;return; } if(deep+H(s)>limit) return; char u[10]; getstr(s); for(int i=0;i<=9;i++) u[i]=t[i]; int a=pos/3,b=pos%3; for(int i=0;i<4;i++) { if(pre_dir==0&&i==1) continue; if(pre_dir==1&&i==0) continue; if(pre_dir==2&&i==3) continue; if(pre_dir==3&&i==2) continue; int x=a+dir[i][0],y=b+dir[i][1]; if(!g(x,y)) continue; int new_pos=3*x+y; swap(u[pos],u[new_pos]); for(int i=0;i<=9;i++) t[i]=u[i]; int new_s=getnum(); path[deep]=i; dfs(new_pos,new_s,deep+1,i); if(flag) return; swap(u[pos],u[new_pos]); } } 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; } for(int i=0;i<9;i++) { if(input[i]!='x') continue; limit=H(getnum()); flag=0; while(!flag) { for(int i=0;i<=9;i++) t[i]=input[i]; int ggg=getnum(); dfs(i,ggg,0,-1); if(flag) break; limit++; } for(int i=0;i<limit;i++) printf("%c",d[path[i]]); printf("\n"); } } return 0; }