题意
在一个 5 ∗ 5 5*5 5∗5的棋盘上有 12 12 12个白骑士和 12 12 12个黑骑士,以及 1 1 1个空格,骑士可以按照“日”字型行走,计算从棋盘初始状态到达目标状态的最小步数,如果无法在 15 15 15步之内达到目标状态,输出 − 1 -1 −1。
目标状态图:
题解
IDA*
IDA控制搜索深度,每次通过
8
8
8个方向移动空格的位置,不需要记录状态也不需要判重。
A*剪枝,启发函数为未归位的棋子个数,评价函数为当前步数加上未归位的棋子个数。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int T,dir[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
char target[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'}
};
char a[5][5];
bool f;
bool check(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(a[i][j]!=target[i][j]) return false;
}
}
return true;
}
bool eva(int dep,int cur){
int cnt=cur;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(a[i][j]!=target[i][j]){
cnt++;
}
}
}
return cnt<=dep;
}
void dfs(int x,int y,int dep,int cur){
if(cur>dep) return;
if(cur==dep){
if(check()){
f=true;
return;
}
}
for(int i=0;i<8;i++){
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(tx>=0 && tx<5 && ty>=0 && ty<5){
swap(a[x][y],a[tx][ty]);
if(eva(dep,cur)) dfs(tx,ty,dep,cur+1);
swap(a[x][y],a[tx][ty]);
if(f) return;
}
}
}
int main(){
scanf("%d",&T);
while(T--){
for(int i=0;i<5;i++){
scanf("%s",a+i);
}
int sx=-1,sy=-1;
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
if(a[i][j]=='*'){
sx=i;
sy=j;
break;
}
}
if(sx!=-1) break;
}
f=false;
for(int i=0;i<16;i++){
dfs(sx,sy,i,0);
if(f){
printf("%d\n",i);
break;
}
}
if(!f) printf("-1\n");
}
}