传送门
题目描述:
在一个 5 × 5 5×5 5×5 的棋盘上有 12 12 12 个白色的骑士和 12 12 12 个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为 1 1 1 ,纵坐标相差为 2 2 2 或者横坐标相差为 2 2 2 ,纵坐标相差为 1 1 1 的格子)移动到空位上。
给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘:
为了体现出骑士精神,他们必须以最少的步数完成任务。
输入格式:
第一行有一个正整数 t t t( t t t ≤ 10 10 10),表示一共有 t t t 组数据。
接下来有 t t t 个 5 × 5 5×5 5×5 的矩阵, 0 0 0 表示白色骑士, 1 1 1 表示黑色骑士, ∗ * ∗ 表示空位。两组数据之间没有空行。
输出格式:
对于每组数据都输出一行。如果能在 15 15 15 步以内(包括 15 15 15 步)到达目标状态,则输出步数,否则输出 − 1 -1 −1 。
样例数据:
输入
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
输出
7
-1
备注:
题解:IDA*(我觉得就是迭代加深和 A* 的结合)
看到数据范围最多移动 15 15 15 次,很容易想到搜索,但爆搜显然是不行的,要想办法优化,于是想到这几个搜索优化
首先是由于最多走 15 15 15 步,很容易想到迭代加深,不断加大深度来判断当前的深度是否合法
然后就是用 A* 优化,这道题的估价函数是很好写的,由于每次移动最多使一个骑士到位,所以统计一下当前没有到位的骑士就是估计值了
直接用骑士来 d f s dfs dfs 不太好做,我们就想到用空格的移动来 d f s dfs dfs(因为每次移动空格的位置都会变)
#include
#include
#include
#include
using namespace std;
int h,flag,a[10][10];
int tx[10]={0,1,1,2,2,-2,-2,-1,-1};
int ty[10]={0,2,-2,1,-1,1,-1,2,-2};
int goal[7][7]={
{0,0,0,0,0,0},
{0,1,1,1,1,1},
{0,0,1,1,1,1},
{0,0,0,2,1,1},
{0,0,0,0,0,1},
{0,0,0,0,0,0}
};
int eva()
{
int i,j,num=0;
for(i=1;i<=5;++i)
for(j=1;j<=5;++j)
if(a[i][j]!=goal[i][j])
num++;
return num;
}
void A_star(int x,int y,int dep)
{
if(dep==h)
{
if(!eva())
flag=true;
return;
}
int i,xx,yy;
for(i=1;i<=8;++i)
{
xx=x+tx[i];
yy=y+ty[i];
if(xx>=1&&xx<=5&&yy>=1&&yy<=5)
{
swap(a[x][y],a[xx][yy]);
if(eva()+dep<=h)
A_star(xx,yy,dep+1);
swap(a[x][y],a[xx][yy]);
}
}
}
int main()
{
char c;
int n,i,j,sx,sy;
scanf("%d",&n);
while(n--)
{
for(i=1;i<=5;++i)
{
for(j=1;j<=5;++j)
{
cin>>c;
a[i][j]=c-'0';
if(c=='*') a[i][j]=2,sx=i,sy=j;
}
}
if(!eva()) {printf("0\n");continue;}
flag=0;
for(h=1;h<=15;++h)
{
A_star(sx,sy,0);
if(flag) {printf("%d\n",h);goto end;}
}
printf("-1\n");
end:;
}
return 0;
}