书上的推荐例题,在双向广搜里面。刚开始尝试用双向广搜,但是一直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[]数组已经被标记了,所以不会出现此类情况。