bzoj 1085: [SCOI2005]骑士精神(IDA*)

1085: [SCOI2005]骑士精神

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 2296   Solved: 1328
[ Submit][ Status][ Discuss]

Description

  在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位。在任何时候一个骑士都能按照骑
士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵坐标相差为1的格子)移动到空
位上。 给定一个初始的棋盘,怎样才能经过移动变成如下目标棋盘: 为了体现出骑士精神,他们必须以最少的步
数完成任务。

Input

  第一行有一个正整数T(T<=10),表示一共有N组数据。接下来有T个5×5的矩阵,0表示白色骑士,1表示黑色骑士,*表示空位。两组数据之间没有空行。

Output

  对于每组数据都输出一行。如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出-1。

Sample Input

2
10110
01*11
10111
01001
00000
01011
110*1
01110
01010
00100

Sample Output

7
-1

IDA*的基本思路:

首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;

如果没有找到解,则加大阈值maxH,再重复上述搜索,直到找到一个解,

在保证H值的计算满足A*算法的要求下,可以证明找到的这个解一定是最优解

IDA*的优点:

在程序实现上,IDA*要比A*方便,因为不需要保存结点,不需要判重复,

也不需要根据H值对结点排序,占用空间小。

而在IDA*算法中也要使用合适的估价函数,来评估与目标状态的距离。

估价函数一般选择:

当前局面的估价函数值+当前的搜索深度>预定义的最大搜索深度时,就进行剪枝。


对于这题,因为限制了步数在15步之内,初始直接将阈值设为0,然后慢慢加到15,也就说先假设0步就能完成,

如果搜不出来,就假设它1步能完成……以此类推直到能完成为止

搜索过程中如果当前局面已经无法在要求步数之内完成了,就直接剪枝


#include<stdio.h>
#include<algorithm>
using namespace std;
int Aim[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 dir[8][2] = {-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1};
int ok, a[5][5];
int check()
{
	int i, j, sum;
	sum = 0;
	for(i=0;i<5;i++)
	{
		for(j=0;j<5;j++)
		{
			if(Aim[i][j]!=a[i][j])
				sum++;
		}
	}
	return sum;
}
void Sech(int x, int y, int k)
{
	int i, dx, dy;
	if(k==0)
	{
		if(check()==0)
			ok = 1;
		return;
	}
	if(ok)  return;
	for(i=0;i<=7;i++)
	{
		dx = x+dir[i][0];
		dy = y+dir[i][1];
		if(dx<0 || dx>4 || dy<0 || dy>4)
			continue;
		swap(a[x][y], a[dx][dy]);
		if(check()<=k)
			Sech(dx, dy, k-1);
		swap(a[x][y], a[dx][dy]);
	}
}
int main(void)
{
	char ch;
	int T, i, j, x, y;
	scanf("%d", &T);
	while(T--)
	{
		ok = 0;
		for(i=0;i<5;i++)
		{
			for(j=0;j<5;j++)
			{
				scanf(" %c", &ch);
				if(ch=='0')  a[i][j] = 0;
				else if(ch=='1')  a[i][j] = 1;
				else  a[i][j] = 2, x = i, y = j;
			}
		}
		for(i=0;i<=15;i++)
		{
			Sech(x, y, i);
			if(ok)  break;
		}
		if(ok)  printf("%d\n", i);
		else  printf("-1\n");
	}
	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值