HDU1430,魔板
2018-08-31 21:20
92 查看
版权声明:转载需注明出处 https://blog.csdn.net/wysiwygo/article/details/82262140
书上的推荐例题,在双向广搜里面。刚开始尝试用双向广搜,但是一直wa,看网上讨论才知道所得到的答案不一定是最小的字典序。此题比较纠结的是标记,普通做要开8维数组,但是如果用cantor展开之后,每一种状态就可以用一个数字来代表,只用一个一维数组就可以标记了。
另外,要对输入做一下处理:将每一组的初态变成”12345678”,然后末态相应地变成“xxxxxxxx”,这样一来,每次的初态都一样,只是末态不一样,一次bfs()将所有的情况的结果都打表,然后每输入一个末态,直接输出答案,这样才不会超时。现在的问题是:初态变成”12345678“之后,怎样将末态变成相应的”xxxxxxxx”,答案才不会错。举个例子:比如初态是“63728145”,将初态处理成“12345678”之后,发生的改变是6->1,3->2,7->3,2->4,8->5,1->6,4->7,5->8假若末态为“54716328”,由于初态发生了改变,所以末态也要依照相同的规则进行改变,所以末态应该变为“54716328”->”87361245”,代码的实现为:
注:start[8]是初态,end[8]是末态,f[8]是对应的变换的值,比如上面就是f[6]=1
//处理f[8]数组 for (int i=0; i<8; i++) { f[start[i]]=i+1;//上面就是f[6]=1,f[3]=2等等 } //处理end[8]数组,start[8]不用管了,直接就是12345678 for (int i=0; i<8; i++) { end[i]=f[end[i]];//原来是多少,按照f(x)进行变换 }
做好了上面的工作,下面的,应该问题就不大了,代码如下:
/************************************************************************* > File Name: main.cpp > Author:Eagles > Mail:None > Created Time: 2018年08月31日 星期五 14时21分37秒 > Description:HDU1430 ************************************************************************/ #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<queue> #include<string> #include<algorithm> using namespace std; int factorial[]={1,1,2,6,24,120,720,5040,40320};//阶乘 bool vis[46300];//标记数组 string ans[46300];//打表 struct node { char nums[2][4];//八个数字,我用的是char string s;//存储操作A、B、C void A()//A操作,下同 { for (int i=0; i<4; i++) { char tmp=nums[0][i]; nums[0][i]=nums[1][i]; nums[1][i]=tmp; } s+='A'; } void B() { char tmp1=nums[0][3]; char tmp2=nums[1][3]; for (int i=3; i>0;i--) { nums[0][i]=nums[0][i-1]; nums[1][i]=nums[1][i-1]; } nums[0][0]=tmp1; nums[1][0]=tmp2; s+='B'; } void C() { char tmp=nums[0][1]; nums[0][1]=nums[1][1]; nums[1][1]=nums[1][2]; nums[1][2]=nums[0][2]; nums[0][2]=tmp; s+='C'; } int cantor()//获得cantor值,就好比人的身份证,每个状态都只有唯一的值 { int val=0; char tmp[8]; for (int i=0; i<4; i++) tmp[i]=nums[0][i]; for (int i=3; i>=0; i--) tmp[7-i]=nums[1][i]; for (int i=0; i<7; i++) { int smaller=0; for (int j=i+1; j<8; j++) if(tmp[i]>tmp[j]) smaller++; val+=smaller*factorial[8-1-i]; } return val; } }s,e,cur,nex;//s是开始,e是结束,cur是当前,nex是下一个 void bfs() { memset(vis,false,sizeof(vis)); vis[s.cantor()]=true; ans[s.cantor()]='\n'; queue<node>Q; Q.push(s); while (!Q.empty()) { cur=Q.front(); Q.pop(); for (int i=0; i<3; i++) { nex=cur; switch(i) { case 0: nex.A();break; case 1: nex.B();break; case 2: nex.C();break; } if(!vis[nex.cantor()]) { vis[nex.cantor()]=true; ans[nex.cantor()]=nex.s; Q.push(nex); } } } } int main() { // freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); char tmp[9]; //使s的八个数字为"12345678" for (int i=0; i<4; i++) s.nums[0][i]=i+1+'0'; for (int i=3; i>=0; i--) s.nums[1][i]=8-i+'0'; bfs(); while (cin>>tmp) { int f[9]; for (int i=0; i<8; i++) f[tmp[i]-'0']=i+1; cin>>tmp; //使e的八个数字相应地改变 for (int i=0; i<4; i++) e.nums[0][i]=f[tmp[i]-'0']+'0'; for (int i=3; i>=0; i--) e.nums[1][i]=f[tmp[7-i]-'0']+'0'; if (e.cantor()==0) cout<<endl; else cout<<ans[e.cantor()]<<endl; } return 0; }
我当时还有一点比较疑惑,就是怕答案中出现类似”AA”,”BBBB”,”CCCC”的东西,但实际上不会出现,因为:出现AA,BBBB,CCCC,就回到上一步操作了,而上一步的vis[]数组已经被标记了,所以不会出现此类情况。
阅读更多相关文章推荐
- HDU 1430 魔板
- HDU 1430 魔板
- HDU - 1430 魔板 (bfs预处理 + 康托)
- hdu 1430 魔板(bfs+预处理+康托展开)
- hdu 1430 魔板
- ACM-康托展开+预处理BFS之魔板——hdu1430
- [HDU 1430] 魔板
- hdu 1430 魔板 康托展开 + 很好的映射
- HDU 1430 魔板
- hdu 1430 魔板
- hdu 1430 魔板
- HDU 1430 魔板
- HDU_1430——魔板,预处理,康托展开,置换,string类的+操作
- HDU 1430 魔板
- HDU-1430 魔板
- hdu 1430 魔板(bfs+康拓展开)
- HDU 1430 魔板 康托展开或字典树 + BFS
- HDU 1430 魔板 搜索
- HDU-1430 魔板
- HDU 1430 魔板(BFS+HASH+置换)