Description
像骑士的忠贞
不畏惧邪恶的眼神
这过程一直放在我心底就像
挡在你胸前的盔甲
保护着我让我心疼
骑士们发挥出你们的精神
就这样强悍的骑士撑到最后
骄傲的公主的要回家整装再出发。
这是蔡依林的歌曲骑士精神,听歌归听歌,题还是得做。题目要求在一个5×5的棋盘上放12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步数完成任务。
Input
第一行有一个正整数T(T <= 10) 表示一共有T组数据 接下来有T个5*5的矩形。0表示白色骑士1表示黑色骑士,*表示空位。(每组数据间有空行)
Output
对每组数据都输出一行。如果能在10步以内(包括10)到达目标状态,则输出步数,否则输出-1。
Sample Input
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
Sample Output
7
-1
题解
直接搜索所有可能的局面,并使用估计函数剪枝即可。在估计函数中,每次遍历统计当前局面与目标局面不同棋子的个数,考虑一步可以交换两个棋子的位置,将不同棋子的个数除以2,即可以得出当前局面到目标局面的最优情况还需几步。若最优步数+当前搜索深度>10,则该局面必定不能到达目标局面,就可以剪枝。
此外,若当前深度大于等于之前已经搜索出的解,也可剪枝。
代码
#include<iostream>
#include<queue>
#define ll long long
using namespace std;
char v[5][5];
const char a[5][5]={
'1','1','1','1','1',
'0','1','1','1','1',
'0','0','*','1','1',
'0','0','0','0','1',
'0','0','0','0','0'
};
const int nextx[8]={-2,-1,1,2,2,1,-1,-2};
const int nexty[8]={1,2,2,1,-1,-2,-2,-1};
int ans=-1;
int dis(){
int disCnt=0;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(a[i][j]!=v[i][j]){
disCnt++;
}
}
}
return disCnt/2;
}
void dfs(int cnt,int x,int y){
if(cnt>10){
return;
}
if(ans!=-1&&cnt>=ans){
return;
}
int maxStep=dis();
if(maxStep==0){
if(ans==-1){
ans=cnt;
}
else{
ans=min(ans,cnt);
}
return;
}
if(cnt+maxStep>10){
return;
}
for(int i=0;i<8;++i){
int tx=x+nextx[i];
int ty=y+nexty[i];
if(tx<0||tx>=5||ty<0||ty>=5){
continue;
}
swap(v[x][y],v[tx][ty]);
dfs(cnt+1,tx,ty);
swap(v[tx][ty],v[x][y]);
}
return;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int t;
cin>>t;
while(t--){
ans=-1;
int x,y;
for(int i=0;i<5;++i){
for(int j=0;j<5;j++){
cin>>v[i][j];
if(v[i][j]=='*'){
x=i;
y=j;
}
}
}
dfs(0,x,y);
cout<<ans<<endl;
}
return 0;
}