UVA_10422

一开始本来打算用BFS+Hash判重去做,但是空格有些不好处理,后来发现由于限定了解的层数最多为10,那么直接用DFS也不是很困难的事情。

如果直接DFS,节点数是8^10,还是有些多了,但我们可以进行适当的剪枝,我想的剪枝策略有下面两个:

①当n=9时,如果空格与中心的曼哈顿距离不等于3,那么就不用再往下搜了,肯定无解。如果曼哈顿距离为3,那么第10步空格一定会走到中央。

②对于当前状态,假如已经移动了n步,我们统计所得的棋盘主对角线及其上部白马的个数为p,如果p-2>10-n,也不用继续往下搜了,肯定无解。因为上半部分白马的容量最多为2p-2为多余的白马,剩余可走步数至少应该让这些多余的白马全走出来。

#include<stdio.h>
#include
<string.h>
#include
<math.h>
int target[5][5]={{1,1,1,1,1},{0,1,1,1,1},
{
0,0,-1,1,1},{0,0,0,0,1},{0,0,0,0,0}};
int a[5][5],ans;
char b[10];
int dx[]={-2,-2,-1,1,2,2,1,-1};
int dy[]={-1,1,2,2,1,-1,-2,-2};
void dfs(int x,int y,int n)
{
int i,j,k,p,num,newx,newy;
if(memcmp(a,target,sizeof(target))==0)
{
if(n<ans)
ans
=n;
return;
}
if(n==9)
{
p
=abs(x-2)+abs(y-2);
if(p!=3)
return;
k
=a[x][y];
a[x][y]
=a[2][2];
a[
2][2]=k;
if(memcmp(a,target,sizeof(target))==0&&10<ans)
ans
=10;
a[
2][2]=a[x][y];
a[x][y]
=k;
return;
}
p
=0;
for(i=0;i<5;i++)
for(j=i;j<5;j++)
if(a[i][j]==0)
p
++;
if(p-2>10-n)
return;
for(i=0;i<8;i++)
{
newx
=x+dx[i];
newy
=y+dy[i];
if(newx>=0&&newx<5&&newy>=0&&newy<5)
{
k
=a[x][y];
a[x][y]
=a[newx][newy];
a[newx][newy]
=k;
dfs(newx,newy,n
+1);
a[newx][newy]
=a[x][y];
a[x][y]
=k;
}
}
}
int main()
{
int i,j,k,x,y,N,t;
gets(b);
sscanf(b,
"%d",&N);
while(N--)
{
for(i=0;i<5;i++)
{
gets(b);
for(j=0;j<5;j++)
{
if(b[j]==' ')
{
a[i][j]
=-1;
x
=i;
y
=j;
}
else
a[i][j]
=b[j]-'0';
}
}
ans
=11;
dfs(x,y,
0);
if(ans<11)
printf(
"Solvable in %d move(s).\n",ans);
else
printf(
"Unsolvable in less than 11 move(s).\n");
}
return 0;
}

  

posted on 2011-09-11 20:14  Staginner  阅读(589)  评论(0编辑  收藏  举报