题目大意
有一个神奇的游戏,有一个#字形的界面。
每次有八种操作,如图:
定义最终状态为中间八个格子都是同一个数。
现在给出一种界面,问最少几步可以到达最终状态。
第一行输出每次操作。如果有多组解,输出字典序最小的一组,如果不用移动,输出“No moves needed”。
第二行输出最终状态中间八个格子的数字。
题解
输入格式比较坑,还不知道有什么好方法,于是我就直接一个一个格子读入了。
显然直接爆搜是不行的。
既然要优化,首先要确定用深搜还是广搜。
如果用广搜,貌似状态不怎么好记,不过貌似看到一种神奇的做法,先枚举中间最后是什么数字,然后记录这些数字的位子作为状态,直接广搜。暂时没想明白。
于是我用了深搜。
我直接人工模拟每个操作,然而实际上这些操作是可以打表的,所以我代码比较冗长。
这种寻找最小步数的题,可以使用迭代加深弥补dfs的不足。
然而这样还是过不了这题。
于是转向去寻找一个启发式函数,进行idA*。
一开始,我把每个位置里中心八个块的最短距离加起来,就可以得到每个数字的一个启发值,就取最小的那个。
但是这样是错的,因为一次移动可能导致好几个块的最短距离减小。
所以应该求最大值,加了这个优化之后,代码就可以过了。
#include <cstdio>
#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
using namespace std;
int A[10][10],H[10][10];
inline void rd(int&res){
res=0;char c;
while(c=getchar(),!isdigit(c));
do res=res*10+(c^48);
while(c=getchar(),isdigit(c));
}
int ans=0,sz;
char res[10];
int H_function(){
int tmp[4]={0};
int mx[4]={0};
for(int i=1;i<=7;i++)
mx[A[3][i]]=max(mx[A[3][i]],H[i][3]);
for(int i=1;i<4;i++)
tmp[i]+=mx[i],mx[i]=0;
for(int i=1;i<=7;i++)
mx[A[5][i]]=max(mx[A[5][i]],H[i][5]);
for(int i=1;i<4;i++)
tmp[i]+=mx[i],mx[i]=0;
for(int i=1;i<=7;i++)
mx[A[i][3]]=max(mx[A[i][3]],H[3][i]);
for(int i=1;i<4;i++)
tmp[i]+=mx[i],mx[i]=0;
for(int i=1;i<=7;i++)
mx[A[i][5]]=max(mx[A[i][5]],H[5][i]);
for(int i=1;i<4;i++)
tmp[i]+=mx[i],mx[i]=0;
return min(tmp[1],min(tmp[2],tmp[3]));
}
void dfs(int dep){
if(ans) return;
if(dep<0) return;
int h=H_function();
if(h==0){
ans=A[3][3];
return;
}
if(dep<h) return;
int B[8][8]={0};
for(int i=1;i<=7;i++)
for(int j=1;j<=7;j++)
B[i][j]=A[i][j];
//A
//
A[3][7]=B[3][1];
for(int i=1;i<7;i++)
A[3][i]=B[3][i+1];
dfs(dep-1);
if(ans){
res[sz++]='A';
return;
}
for(int i=1;i<=7;i++)
A[3][i]=B[3][i];
//
A[5][7]=B[5][1];
for(int i=1;i<7;i++)
A[5][i]=B[5][i+1];
dfs(dep-1);
if(ans){
res[sz++]='B';
return;
}
for(int i=1;i<=7;i++)
A[5][i]=B[5][i];
//
for(int i=2;i<=7;i++)
A[i][3]=B[i-1][3];
A[1][3]=B[7][3];
dfs(dep-1);
if(ans){
res[sz++]='C';
return;
}
for(int i=1;i<=7;i++)
A[i][3]=B[i][3];
//
for(int i=2;i<=7;i++)
A[i][5]=B[i-1][5];
A[1][5]=B[7][5];
dfs(dep-1);
if(ans){
res[sz++]='D';
return;
}
for(int i=1;i<=7;i++)
A[i][5]=B[i][5];
//
A[5][1]=B[5][7];
for(int i=2;i<=7;i++)
A[5][i]=B[5][i-1];
dfs(dep-1);
if(ans){
res[sz++]='E';
return;
}
for(int i=1;i<=7;i++)
A[5][i]=B[5][i];
//
A[3][1]=B[3][7];
for(int i=2;i<=7;i++)
A[3][i]=B[3][i-1];
dfs(dep-1);
if(ans){
res[sz++]='F';
return;
}
for(int i=1;i<=7;i++)
A[3][i]=B[3][i];
//
for(int i=1;i<7;i++)
A[i][5]=B[i+1][5];
A[7][5]=B[1][5];
dfs(dep-1);
if(ans){
res[sz++]='G';
return;
}
for(int i=1;i<=7;i++)
A[i][5]=B[i][5];
//
for(int i=1;i<7;i++)
A[i][3]=B[i+1][3];
A[7][3]=B[1][3];
dfs(dep-1);
if(ans){
res[sz++]='H';
return;
}
for(int i=1;i<=7;i++)
A[i][3]=B[i][3];
}
void solve(){
ans=0;
rd(A[5][1]);rd(A[3][2]);rd(A[5][2]);
for(int i=1;i<=7;i++)
rd(A[i][3]);
rd(A[3][4]);rd(A[5][4]);
for(int i=1;i<=7;i++)
rd(A[i][5]);
rd(A[3][6]);rd(A[5][6]);
rd(A[3][7]);rd(A[5][7]);
sz=0;
for(int i=0;;i++){
dfs(i);
if(ans){
if(sz){
for(int w=sz-1;w>=0;w--)
printf("%c",res[w]);
puts("");
}else puts("No moves needed");
printf("%d\n",ans);
return;
}
}
}
int main(){
H[1][3]=H[1][5]=H[3][1]=H[5][1]=H[7][3]=H[7][5]=H[3][7]=H[5][7]=2;
H[2][3]=H[2][5]=H[3][2]=H[5][2]=H[6][3]=H[6][5]=H[3][6]=H[5][6]=1;
while(rd(A[3][1]),A[3][1]) solve();
return 0;
}