原题链接:Here!
分析:求经过若干次四个操作 ' r ' , ' l ' , ' u ' , ' d ' 到状态1 2 3 4 5 6 7 8 x,输出操作顺序。因为最终状态一定,所以采用反向BFS打表,记录路径即可。
CODE:
/*
Note:
因为题目要求是任意状态求是否能到一个"完美状态",因为任意状态不确定性和完美状态的确定性,所以不妨
反向BFS+打表
抠脚
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<queue>
using namespace std;
#define test
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
int Cantor(int *s,int n){ // 康托展开
int ans=0;
for(int i=0;i<n;i++){
int tmp=0;
for(int j=i+1;j<n;j++)
if(s[i]>s[j]) tmp++;
ans += tmp*fac[n-1-i];
}
return ans;
}
void unCantor(int index,int *t,int n){ // 康托逆展开
index--;
int i,j;
int vis[10]={0};
for(i=0;i<n;i++){
int tmp=index/fac[n-1-i];
for(j=0;j<=tmp;j++)
if(vis[j]) tmp++;
t[i]=tmp+1;
vis[tmp]=1;
index%=fac[n-1-i];
}
}
const int maxn = 362880; // 9! = 362880
bool can[maxn]; // 记录状态是否出现
char ans[maxn][42]; // 打个表将答案打到一个二维数组中,第一维是Cantor值,然后是一个字符串
int target[]={1,2,3,4,5,6,7,8,0}; // 目标状态
int tt[9];
struct Node{ // Node的信息代表 key是空白点在(x,y)的状态下的康托值,tol是拓展层数
int key,x,y,tol;
Node(int _key,int _x,int _y,int _tol):key(_key),x(_x),y(_y),tol(_tol){}
};
queue<Node> q;
void bfs(){
// 初始化
memset(can,false,sizeof(can));
while(!q.empty()) q.pop();
int t_key=Cantor(target,9); // 找到目标状态康托值
can[t_key]=true;
ans[t_key][0]='\0';
q.push(Node(t_key,2,2,0)); // 3x3 初始点x在(2,2)
while(!q.empty()){
Node tmp=q.front(); q.pop();
unCantor(tmp.key+1,tt,9); // 将Cantor值对应的状态录入到数组tt中
int x=tmp.x, y=tmp.y;
// 接下来4个if 代表上下左右走,因为是倒序BFS所以向上走时就是原来的向下走,其他相同
if(x>=1){ // 倒序向上走
swap(tt[x*3+y],tt[(x-1)*3+y]); // 交换两个格子
t_key=Cantor(tt,9);
if(!can[t_key]){
q.push(Node(t_key,x-1,y,tmp.tol+1)); // 记录向上走后的状态,然后tol+1
can[t_key]=true;
for(int i=0;i<tmp.tol;i++) ans[t_key][i]=ans[tmp.key][i]; // *继承父亲的路径
ans[t_key][tmp.tol]='d';
ans[t_key][tmp.tol+1]='\0';
}
swap(tt[x*3+y],tt[(x-1)*3+y]); // 为什么每次都要交换过来,如果不能交换,当然得保持原样
}
if(y>=1){ // 倒序向左走
swap(tt[x*3+y],tt[x*3+(y-1)]);
t_key=Cantor(tt,9);
if(!can[t_key]){
q.push(Node(t_key,x,y-1,tmp.tol+1));
can[t_key]=true;
for(int i=0;i<tmp.tol;i++) ans[t_key][i]=ans[tmp.key][i];
ans[t_key][tmp.tol]='r';
ans[t_key][tmp.tol+1]='\0';
}
swap(tt[x*3+y],tt[x*3+(y-1)]);
}
if(x<=1){ // 倒序向下走
swap(tt[x*3+y],tt[(x+1)*3+y]);
t_key=Cantor(tt,9);
if(!can[t_key]){
q.push(Node(t_key,x+1,y,tmp.tol+1));
can[t_key]=true;
for(int i=0;i<tmp.tol;i++) ans[t_key][i]=ans[tmp.key][i];
ans[t_key][tmp.tol]='u';
ans[t_key][tmp.tol+1]='\0';
}
swap(tt[x*3+y],tt[(x+1)*3+y]);
}
if(y<=1){ // 倒序向右走
swap(tt[x*3+y],tt[x*3+(y+1)]);
t_key=Cantor(tt,9);
if(!can[t_key]){
q.push(Node(t_key,x,y+1,tmp.tol+1));
can[t_key]=true;
for(int i=0;i<tmp.tol;i++) ans[t_key][i]=ans[tmp.key][i];
ans[t_key][tmp.tol]='l';
ans[t_key][tmp.tol+1]='\0';
}
swap(tt[x*3+y],tt[x*3+(y+1)]);
}
}
}
int d[9]; // 存放目标状态
void solve(){
int t_key=Cantor(d,9);
if(!can[t_key]){ printf("unsolvable\n"); return; }
int len=strlen(ans[t_key]);
for(int i=len-1;i>=0;i--)
printf("%c",ans[t_key][i]);
printf("\n");
}
int main(){
bfs(); // 反向BFS打表
#ifdef test
freopen("Hdu 1043 Eight.txt","r",stdin);
#endif
string op;
while(getline(cin,op)){
for(int i=0,j=0;i<op.size();i++){
if(op[i]>='1' && op[i]<='8')
d[j++]=op[i]-'0';
if(op[i]=='x')
d[j++]=0;
}
solve();
}
return 0;
}