八数码第四境界——暴力反向BFS+康托展开判重+打表+回溯记录路径
(请先看前面3重境界)
由于第三重境界要开一个vector来嵌套许多vector来记录路径,那绝对是开销很大。所以我们采用回溯记录路径。
思路:
原来我们是采用康托展开,比如求出12345678x在全排列的第几个(这里无疑是第一个),用来判断这种状态是否已经到达过了,这里就是vis[1]=1代表已经访问过,vis[1]=0代表未访问过。在每次访问以后都置为1。而现在我们这里不一样了。我们存放的是层数。我们这里想要的是路径吧?所以说这里指的就是在这条路径上的第几个,我们的做法就是在最后找到以后,根据这个第几个,来逐一找到上一个,直到找到终点。以前我们每种状态维护的是一个路径,我们这里只需要维护一个操作就可以了。只要我们能把每种状态的路径,和上一种状态的路径,想办法关联起来,就可以了。
用来找到关联的结构体:
1. struct res
2. {
3. int now,fa;
now存放的就是当前的操作(上下左右),fa就是这条路径上上一个状态的操作在这个res数组中存放的地方。就比如说我现在是这个数组的第10个,我的操作是上,我的fa是7,就代表我上一个操作被存放在了7,我们不断去取即可。所以我们一旦让一个点入栈了,也同时会在这个数组的尾端添加一个。赋予他当前的操作是什么,以及这条路径上上一个操作所存放的位置。这个怎么得知呢?因为我们就是通过上一种状态得出下一种状态的,所以我们只需要在上一种状态得出下一种状态的过程中,把他上一种状态所在这个数组中的位置给他,交给他去维护了。所以我们可以得知,这个res数组,并不是有序的。什么意思呢?并不是说这个状态的操作在这里,下一个状态的操作在这个数组的下一个位置,而是通过fa来进行关联。
上个图:
此外,我们上面讲的康托展开,vis[某个节点对应的康托值] = 这个res集合中的某一位,再以此为依据就能回溯出之前的路径了。
讲了这么多理论,具体看看细化的实现。
1. if((h.index+1)%3!=0)
2. {
3. c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
4. h.index++;
5. res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
6. int t=KT(h.str);
7. if(vis[t]==-1)
8. {
9. vis[t]=cnt-1;
10. q.push(h);
11. }
12. }
if语句判断如果不是在最后一列,那就肯定就可以右移。
下一行,和右边那个数进行交换。
h.index指的是x在状态中的位置
res[cnt].now=4,4指代的是右移操作
res[cnt].fa=h.pos这个指的是你上一个状态所在这个res数组的位置赋给你当前状态去维护
h.pos=cnt这是你当前状态所在这个res数组的位置
cnt++你插入了一个数,自然要++,不然接下来还用不用了
最后如果这个位置没有访问过,那么这个状态在vis中的值,也被置为和你当前h.pos位置一样的值。为什么这里也要作文章,因为最后你输出的时候你肯定要根据所要求的结果在res中定位,那你定位的依据是什么?只能以序列通过求康托值得出在vis中的位置,再去取得这个值。
1. if(vis[t]!=-1)
2. {
3. t = vis[t];
4. while(res[t].now!=-1)
5. {
6. if(res[t].now==1)printf("d");
7. if(res[t].now==2)printf("u");
8. if(res[t].now==3)printf("r");
9. if(res[t].now==4)printf("l");
10. t=res[t].fa;
11. }
12. }
13. else
14. printf("unsolvable");
全部代码
- #define N 512345
- char ss[10];
- struct node
- {
- char str[10];
- int pos;
- int index;
- };
- struct res
- {
- int now,fa;
- }res[N];
- int vis[N];
- int fac[] = {1,1,2,6,24,120,720,5040,40320};
- int over,cnt;
- int ans[N];
- int KT(char ss[])
- {
- int i, j, t, sum;
- int s[10];
- for(i=0;i<9;i++)
- {
- if(ss[i]=='x')
- s[i]=0;
- else
- s[i]=ss[i]-'0';
- }
- sum = 0;
- for (i=0; i<9; i++)
- {
- t = 0;
- for (j=i+1; j<9; j++)
- if (s[j] < s[i])
- t++;
- sum += t*fac[9-i-1];
- }
- return sum+1;
- }
- bool bfs()
- {
- char c;
- queue<node> q;
- while(!q.empty())q.pop();
- over = KT(ss);
- node g,h;
- for(int i=0;i<8;i++)
- g.str[i]=i+1+'0';
- g.str[8]='x';g.str[9]='\0';
- g.pos=0;g.index=8;
- int t=KT(g.str);
- vis[t] = 0;
- q.push(g);
- cnt=1;
- while(!q.empty())
- {
- g=q.front();q.pop();
- int t = KT(g.str);
- h=g;
- if((h.index+1)%3!=0)
- {
- c=h.str[h.index];h.str[h.index]=h.str[h.index+1];h.str[h.index+1]=c;
- h.index++;
- res[cnt].now=4;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
- int t=KT(h.str);
- if(vis[t]==-1)
- {
- vis[t]=cnt-1;
- q.push(h);
- }
- }
- h=g;
- if(h.index%3!=0)
- {
- c=h.str[h.index];h.str[h.index]=h.str[h.index-1];h.str[h.index-1]=c;
- h.index--;
- res[cnt].now=3;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
- int t=KT(h.str);
- if(vis[t]==-1)
- {
- vis[t]=cnt-1;
- q.push(h);
- }
- }
- h=g;
- if(h.index<6)
- {
- c=h.str[h.index];h.str[h.index]=h.str[h.index+3];h.str[h.index+3]=c;
- h.index+=3;
- res[cnt].now=2;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
- int t=KT(h.str);
- if(vis[t]==-1)
- {
- vis[t]=cnt-1;
- q.push(h);
- }
- }
- h=g;
- if(h.index>2)
- {
- c=h.str[h.index];h.str[h.index]=h.str[h.index-3];h.str[h.index-3]=c;
- h.index-=3;
- res[cnt].now=1;res[cnt].fa=h.pos;h.pos=cnt;cnt++;
- int t=KT(h.str);
- if(vis[t]==-1)
- {
- vis[t]=cnt-1;
- q.push(h);
- }
- }
- }
- return false;
- }
- int main()
- {
- int i,j,k,kk,t,x,y,z;
- memset(vis,-1,sizeof(vis));
- res[0].now=-1;
- bfs();
- while(scanf("%s",ss)!=EOF)
- {
- for(i=1;i<9;i++)
- scanf("%s",ss+i);
- t = KT(ss);
- if(vis[t]!=-1)
- {
- t = vis[t];
- while(res[t].now!=-1)
- {
- if(res[t].now==1)printf("d");
- if(res[t].now==2)printf("u");
- if(res[t].now==3)printf("r");
- if(res[t].now==4)printf("l");
- t=res[t].fa;
- }
- }
- else
- printf("unsolvable");
- printf("\n");
- }
- return 0;
- }