HDU - 1043 Eight
题意
不会康拓展开的建议看看这篇文章,简单易懂
康托展开
该题可以利用康拓展开模拟出一张hash表,又因为所有的情况不超过370000种,所以可以从123456789(9指代x)进行反向BFS打表暴力A题
而无解的情况也很好判断,只要判断打表过后当前这种情况是否曾经出现过,没有就输出 ``unsolvable’’,否则就从当前情况的方向一直逆推回123456789的情况
以下是代码
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
using namespace std;
const int N = 370000;
int fac[11]= {1};//存阶乘用
bool vv[11];//康托展开需要用到的标记数组
struct node
{
char DIR;//当前方向
int FA;//父节点
} vis[N];//所有的情况
struct Node
{
int inf[11];//当前的8数码情况
int x;//当前X所在位置
int CC;//当前情况的康拓展开数
} stand;
void init()//初始化
{
for(int i=1; i<10; ++i)
fac[i]=fac[i-1]*i;//初始化阶乘
for(int i=1; i<N; ++i)
vis[i].FA=-1;//初始化父节点
vis[0].FA=-100;//把123456789的情况设定为-100,避免混淆
for(int i=0; i<9; ++i)
stand.inf[i]=i+1;//123456789
stand.x=8;//X最初在8的位置(0——8)
stand.CC=0;//最初的康托展开数为0
}
int Cantor(int now[])//康托展开
{
int ans=0,base;
memset(vv,0,sizeof(vv));
for(int i=0; i<8; ++i)
{
base=0;
for(int j=1; j<now[i]; ++j)
if(vv[j]==0)
base++;
vv[now[i]]=1;
ans+=base*fac[8-i];
}
return ans;
}
void BFS()
{
queue<Node>qq;
qq.push(stand);
while(!qq.empty())
{
Node k = qq.front();
qq.pop();
for(int i=0; i<4; ++i)
{
Node kk = k;
if(i==0&&kk.x<3||i==1&&kk.x>5||i==2&&kk.x%3==0||i==3&&kk.x%3==2)//判断是否可以这样移动
continue;
if(i==0)
{
swap(kk.inf[kk.x],kk.inf[kk.x-3]);
kk.x-=3;
kk.CC=Cantor(kk.inf);
if(vis[kk.CC].FA!=-1)//是否标记过
continue;
vis[kk.CC].DIR='d';//字母是反着的,方便最后输出
}
else if(i==1)
{
swap(kk.inf[kk.x],kk.inf[kk.x+3]);
kk.x+=3;
kk.CC=Cantor(kk.inf);
if(vis[kk.CC].FA!=-1)
continue;
vis[kk.CC].DIR='u';
}
else if(i==2)
{
swap(kk.inf[kk.x],kk.inf[kk.x-1]);
kk.x-=1;
kk.CC=Cantor(kk.inf);
if(vis[kk.CC].FA!=-1)
continue;
vis[kk.CC].DIR='r';
}
else
{
swap(kk.inf[kk.x],kk.inf[kk.x+1]);
kk.x+=1;
kk.CC=Cantor(kk.inf);
if(vis[kk.CC].FA!=-1)
continue;
vis[kk.CC].DIR='l';
}
vis[kk.CC].FA=k.CC;
qq.push(kk);
}
}
return ;
}
int main()
{
char ss[33];
int now[11];
init();
BFS();
while(gets(ss))//输入一行
{
for(int i=0,j=0; ss[i]; ++i)
{
if(ss[i]=='x')
now[j++]=9;
else if(ss[i]>='1'&&ss[i]<'9')
now[j++]=ss[i]-'0';
}
int cc=Cantor(now);
if(vis[cc].FA==-1)//判断是否标记过
{
printf("unsolvable\n");
continue;
}
while(vis[cc].FA!=-100)//逆推输出过程
{
printf("%c",vis[cc].DIR);
cc=vis[cc].FA;
}
printf("\n");
}
return 0;
}