HDU 1043 Eight
HDU 3567-Eight II
HDU 1430 魔板
这两道题很像,在这里我们看第二道,第一道比第二道简单好多;
题目意思是给你起始和终止状态让你输出路径要求字典序最小;
X代表空的位置每次X都可以和相应的上下左右互换位置,让求最终换到终止状态的路径字典序最小;
每一次都求一遍肯定会超时,因为每一种起始状态可以对应18W多的终止状态,200次;
在这里可以看一下第三题,里面有一个很好的思想,就是当终止状态固定是,我们可以通过对终止状态预处理每次只需要回溯输出路径即可;
可以根据终止状态求出起始状态所对应的状态,再在相应的表里找到路径;由于X的位置有9种所以要分别预处理这9种状态;
还有字典序是最坑的,因为我太天真了,以为反向按照字典序最大的搜,反过来输出就是字典序最小了,但是这种思路是错的,具体的根据下面的样例自己参悟;
85472X136
37681245X
这组数据的两种不同结果:
正确的:dluurddluuldrrdlluruldrdr
错误的:dluurdluldrdruldluruldrdr
错的就是因为反向搜反向输出的结果;
用康托展开映射,注意要少用string会超时的太费时间了;
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
struct zp
{
int Hash;//字符串对应的康拓值
int ko;//X的位置
} w;
int HASH[9]= {1,1,2,6,24,120,720,5040,40320};
int Z=1;
int flag[9][400010][3];
int z[9][4]= {3,-1,1,-1,4,0,2,-1,5,1,-1,-1,6,-1,4,0,7,3,5,1,8,4,-1,2,-1,-1,7,3,-1,6,8,4,-1,7,-1,5};
string SS;
void get_nhash(int s)//逆康拓
{
SS="";
char ans[10]= {"123456789"};
for(int i=0; i<9; i++)
{
int y=s/HASH[8-i];
s%=HASH[8-i];
int sum=-1;
for(int j=0; j<9; j++)
{
if(ans[j]!='0')
sum++;
if(sum==y)
{
SS+=ans[j];
ans[j]='0';
break;
}
}
}
}
int get_Hash()//康拓
{
int ans=0;
for(int i=0; i<9; i++)
{
int sum=0;
for(int j=i; j<9; j++)
{
if(SS[j]<SS[i])
sum++;
}
ans+=sum*HASH[8-i];
}
return ans;
}
char get_ans(int a)//路径
{
switch(a)
{
case 0:
return 'd';
break;
case 1:
return 'l';
break;
case 2:
return 'r';
break;
case 3:
return 'u';
break;
}
}
void print(int v,int ko)//回溯输出路径
{
string ans="";
while(flag[ko][v][2]!=-10)
{
ans+=get_ans(flag[ko][v][1]);
v=flag[ko][v][2];
}
printf("Case %d: %d\n",Z++,ans.size());
for(int i=ans.size()-1;i>=0;i--)
printf("%c",ans[i]);
printf("\n");
}
void bfs(string s,int a)//预处理
{
SS=s;
w.Hash=get_Hash();
w.ko=a;
queue<zp> q;
flag[a][w.Hash][0]=1;
flag[a][w.Hash][1]=-5;
flag[a][w.Hash][2]=-10;
q.push(w);
while(!q.empty())
{
zp v=q.front();
q.pop();
get_nhash(v.Hash);
for(int i=0; i<4; i++)
{
if(z[v.ko][i]!=-1)
{
zp u=v;
swap(SS[v.ko],SS[z[v.ko][i]]);
u.Hash=get_Hash();
swap(SS[v.ko],SS[z[v.ko][i]]);
if(flag[a][u.Hash][0]==-1)
{
flag[a][u.Hash][0]=1;//判重
flag[a][u.Hash][1]=i;//方向
flag[a][u.Hash][2]=v.Hash;//父节点
u.ko=z[v.ko][i];
q.push(u);
}
}
}
}
}
void init()//预处理的九种状态
{
string ss[10]= {"912345678","192345678","129345678","123945678","123495678","123459678","123456978","123456798","123456789"};
for(int i=0; i<9; i++)
{
bfs(ss[i],i);
}
}
void solve(string a,string b)
{
string c=b;
int cont=1,ko=0;
for(int i=0; i<9; i++)
{
if(a[i]=='9')
{
ko=i;
continue;
}
for(int j=0; j<9; j++)
{
if(b[j]==a[i])
{
c[j]=cont+'0';
cont++;
break;
}
}
}//将a固定成1-8有序的c就是b变化后的样子,X的位置不能变
SS=c;
int ans=get_Hash();
print(ans,ko);
}
int main()
{
memset(flag,-1,sizeof(flag));
init();
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
string a,b;
cin>>a>>b;
for(int i=0; i<9; i++)
{
if(a[i]=='X')
a[i]='9';
if(b[i]=='X')
b[i]='9';
}
solve(a,b);
}
}