第一次做这种八数码的问题,本来以为要用A*等算法,但这个题后来发现只要做到状态压缩的话直接BFS似乎就已经足够了。
状态压缩采用了康托展开的方法(具体百度),然后在最开始预处理就先把所有的答案算出来,最后直接输出即可。
中间还有些地方可以优化~时间应该可以更快。
代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<queue> #include<iostream> using namespace std; int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; const int maxn=10e5+10; struct node { int num; int ans; int pos; }; bool vis[maxn]; int ans[maxn]; int GetNum(const int *s) { int i, j, temp, num,len=9; num=0; for(i=0;i<len-1;i++) { temp=0; for(j=i+1;j<len;j++) if(s[j]<s[i]) temp++; num+=fac[s[i]-1]*temp; } return num; } void GetNode(int num,int *str) { int n=9; int a[9]; for(int i=2;i<=n;++i) { a[i-1]=num%i; num=num/i; str[i-1]=0; } str[0]=0; int rn, i; for(int k=n;k>=2;k--) { rn=0; for(i=n-1;i>=0;--i) { if(str[i]!=0) continue; if(rn==a[k-1]) break; ++rn; } str[i]=k; } for(i=0;i<n;++i) if(str[i]==0) { str[i]=1; break; } } void BFS() { queue<node> q; q.push((node){0,0,8}); vis[0]=1; ans[0]=0; while(!q.empty()) { node ita=q.front(); int a[9],num,pos=ita.pos; q.pop(); GetNode(ita.num,a); if(ita.pos/3>0) { swap(a[pos],a[pos-3]); num=GetNum(a); if(!vis[num]) { q.push((node){num,ita.ans+1,pos-3}); ans[num]=ita.ans+1; vis[num]=1; } swap(a[pos],a[pos-3]); } if(ita.pos/3<2) { swap(a[pos],a[pos+3]); num=GetNum(a); if(!vis[num]) { q.push((node){num,ita.ans+1,pos+3}); ans[num]=ita.ans+1; vis[num]=1; } swap(a[pos],a[pos+3]); } if(ita.pos%3>0) { swap(a[pos],a[pos-1]); num=GetNum(a); if(!vis[num]) { q.push((node){num,ita.ans+1,pos-1}); ans[num]=ita.ans+1; vis[num]=1; } swap(a[pos],a[pos-1]); } if(ita.pos%3<2) { swap(a[pos],a[pos+1]); num=GetNum(a); if(!vis[num]) { q.push((node){num,ita.ans+1,pos+1}); ans[num]=ita.ans+1; vis[num]=1; } swap(a[pos],a[pos-1]); } } } int main() { node start; char str[9][3]; BFS(); while(scanf("%s",str[0])!=EOF) { for(int i=1;i<9;i++) scanf("%s",str[i]); int a[9]; for(int i=0; i<9; ++i) { if(str[i][0]=='x') a[i]=9; else a[i]=str[i][0]-'0'; } int num=GetNum(a); GetNode(0,a); if(!ans[num]&&num!=0) printf("unsolvable\n"); else printf("%d\n",ans[num]); } return 0; }