題目描述:
在一個5×5的棋盤上有12個白色的騎士和12個黑色的騎士,且有一個空位。在任何時候一個騎士都能按照騎士的走法(它可以走到和它橫座標相差爲1,縱座標相差爲2或者橫座標相差爲2,縱座標相差爲1的格子)移動到空位上。
給定一個初始的棋盤,怎樣才能經過移動變成如下目標棋盤:
爲了體現出騎士精神,他們必須以最少的步數完成任務。
輸入:
輸出:
輸入樣例:
2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100
輸出樣例:
7
-1
思路分析:
根據迭代加深搜索,我們可以將移動步數爲搜索深度,然後步步搜索,然後我們可以用一個目標數組置爲答案。
之後,我們再用一個樂觀估計函數做剪枝,但是可是這該如何定義呢?
我們可以設想,假設我們現在的數組與目標數組的相差值與接下來的可用步數大,
那麼我們不可能得到答案,所以我們可以返回。
代碼實現;
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int find1=0,dx[9]={0,1,1,-1,-1,2,2,-2,-2},dy[9]={0,2,-2,2,-2,1,-1,1,-1},t,a[10][10],sx,sy;
char w;
int goal[5][5]={
{1,1,1,1,1},
{0,1,1,1,1},
{0,0,2,1,1},
{0,0,0,0,1},
{0,0,0,0,0}
};
int check()
{
int dif=0;
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
{
if(goal[i][j]!=a[i][j])
dif++;
}
return dif;
}
void iddfs(int x,int y,int de,int k)
{
if(de==k)
{
if(!check())
find1=1;
return;
}
for(int i=1;i<=8;i++)
{
int x1=x+dx[i];
int y1=y+dy[i];
if(x1<0||x1>4||y1<0||y1>4)
continue;
swap(a[x][y],a[x1][y1]);
if(de+check()<=k)
iddfs(x1,y1,de+1,k);
swap(a[x][y],a[x1][y1]);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
for(int i=0;i<5;i++){
getchar();
for(int j=0;j<5;j++)
{
scanf("%c",&w);
if(w=='*')
{
a[i][j]=2;
sx=i;
sy=j;
}
else
a[i][j]=w-'0';
}
}
int k;
for(k=0;k<=15;k++)
{
iddfs(sx,sy,0,k);
if(find1)
break;
}
if(k>15)
printf("-1\n");
else
printf("%d\n",k);
find1=0;
}
}