poj1077(康托展开+bfs+记忆路径)
题意:就是说,给出一个三行三列的数组,其中元素为1--8和x,例如:
1 2 3 现在,需要你把它变成:1 2 3 要的最少步数的移动方案。可以右移r,左移l,上移u,下移d
x 4 6 4 5 6
7 5 8 7 8 x
思路:这是赤裸裸的康托展开了吧?不知道康托展开的同学可以百度百科........好吧,其实我想说的是,这个题目怎么分析出,要用到康托展开的。首先,遇到这样的题目,元素比较少,又可以用到搜索,但是状态数比较多,也就是说,我需要找到一种方式来压缩这些状态,使得同一个状态不重复出现。额,说道这里,在不考虑时间、空间复杂度的情况下,的确可以直接开标记数组:vist[10][10][10][10][10][10][10][10][10],但是这样一来,会有许多重复的状态。有没有更好压缩状态的方法呢?是有的,进制压缩也是一种方法,只是对于这个题目不适用。那么还有康托展开,康托展开,可以使得这些状态压缩下来,只有9!个状态,如此就可以实现搜索了。
有的人说,广搜不能记录路径?这是错误的,广搜只要你清楚的记录这个状态的上个状态是什么,那么就可以记录路径,很明显只需要开个记录路径的搜索就ok了
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int t[10]= {1,1,2,6,24,120,720,5040,40320}; char ff[400000]; struct node { char ch[10]; int son; int wz; }; struct node1 //记录路径 { char num; int father; } s[362883]; int deal(char str[]) //康托展开 { int x[10],ans1=0; for(int i=0; i<9; i++) x[i]=str[i]-'0'; /*for(int i=0;i<9;i++) printf("%d\t",x[i]);*/ for(int i=0; i<9; i++) { int k=0; for(int j=i+1; j<9; j++) if(x[i]>x[j]) k++; ans1+=k*t[8-i]; //printf("%d %d %d\n",ans1,k,t[8-i]); } return ans1; } int flag=0; void bfs(char str[]) { queue<node>q; node p; strcpy(p.ch,str); p.ch[9]='\0'; p.son=deal(p.ch); // puts(p.ch); p.wz=8; //printf("%d\n",p.son); s[p.son].father=0; q.push(p); while(!q.empty()) { //flag++; //printf("%d\n",flag); p=q.front(); q.pop(); int hang=p.wz/3; int lie=p.wz%3; { int x=hang-1; int y=lie; { int x=hang; int y=lie+1; if(x>=0&&x<3&&y>=0&&y<3&&(x*3+y)<=8) { node p1; strcpy(p1.ch,p.ch); p1.wz=x*3+y; char zf=p1.ch[p.wz]; p1.ch[p.wz]=p1.ch[p1.wz]; p1.ch[p1.wz]=zf; p1.ch[9]='\0'; p1.son=deal(p1.ch); if(s[p1.son].father==-1) { s[p1.son].father=p.son; s[p1.son].num='l'; q.push(p1); } } } { int x=hang; int y=lie-1; if(x>=0&&x<3&&y>=0&&y<3&&(x*3+y)<=8) { node p1; strcpy(p1.ch,p.ch); p1.wz=x*3+y; char zf=p1.ch[p.wz]; p1.ch[p.wz]=p1.ch[p1.wz]; p1.ch[p1.wz]=zf; p1.ch[9]='\0'; p1.son=deal(p1.ch); if(s[p1.son].father==-1) { s[p1.son].father=p.son; s[p1.son].num='r'; q.push(p1); } } } if(x>=0&&x<3&&y>=0&&y<3&&(x*3+y)<=8) { node p1; strcpy(p1.ch,p.ch); p1.wz=x*3+y; char zf=p1.ch[p.wz]; p1.ch[p.wz]=p1.ch[p1.wz]; p1.ch[p1.wz]=zf; p1.ch[9]='\0'; p1.son=deal(p1.ch); if(s[p1.son].father==-1) { s[p1.son].father=p.son; s[p1.son].num='d'; q.push(p1); } } } { int x=hang+1; int y=lie; if(x>=0&&x<3&&y>=0&&y<3&&(x*3+y)<=8) { node p1; strcpy(p1.ch,p.ch); p1.wz=x*3+y; char zf=p1.ch[p.wz]; p1.ch[p.wz]=p1.ch[p1.wz]; p1.ch[p1.wz]=zf; p1.ch[9]='\0'; p1.son=deal(p1.ch); if(s[p1.son].father==-1) { s[p1.son].father=p.son; s[p1.son].num='u'; q.push(p1); } } } } } int main() { char str[10]= {'1','2','3','4','5','6','7','8','0'}; for(int i=0; i<362883; i++) { s[i].father=-1; } //printf("%d\n",flag); bfs(str); char ss[10][10]; char tt[10]; scanf("%s",ss[0]); { if(ss[0][0]!='x') tt[0]=ss[0][0]; else tt[0]='0'; //把x转化为数字0 for(int i=1; i<9; i++) { scanf("%s",ss[i]); if(ss[i][0]!='x') tt[i]=ss[i][0]; else tt[i]='0'; } tt[9]='\0'; //puts(tt); int ans=deal(tt); int cnt=0; flag=0; while(ans!=0) //回溯路径 { ff[cnt++]=s[ans].num; ans=s[ans].father; if(ans==-1) { flag=1; break; } } int i=0; if(flag==0) { while(cnt>i) printf("%c",ff[i++]); } else printf("unsolvable"); printf("\n"); } return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。