POJ3009 Curling 2.0 [IDDFS]

POJ3009 Curling 2.0 \text{POJ3009 Curling 2.0} POJ3009 Curling 2.0

题意简述

有一个冰壶,从起始点开始,经过移动到终点。

移动规则:

  • 可以向一个方向一直运动直到碰到石头。

  • 如果前方就是石头,不能往这个方向移动。

  • 不能出界。

  • 在任何时间移动到终点胜利。

求出最短步数。

题解

算法:IDDFS迭代加深

maxstep控制深度,用Is_Solved表示是否在10步之内有解(输入前更新)。

异于一般DFS的地方:
for(maxstep=1;maxstep<=10&&!DFS(sx,sy,0);maxstep++);

此处的DFS是bool型的,DFS(sx,sy,0)表示从 ( s x , s y ) (sx,sy) (sx,sy)开始,在走不超过 m a x s t e p maxstep maxstep步是否有解。

如此渐渐迭代,不会出现爆栈RE或无止境的情况。

最后输出maxstep即可。

DFS部分:
First of all:判断此时步数是否超过了maxstep,超过先退出。
Then:向4个方向搜。

同一般迷宫类题一样,此处用方向数组。

每一个方向的搜索流程:

  1. 向一个方向一直走,碰到障碍or边界停下。
  2. 判断是因障碍还是边界停下的,若为后者,continue
  3. 如果和原来相比一步都没走(上述题意的第2点),continue
  4. 打碎目前障碍,若:DFS(x,y,step+1)==1,直接return 1;反之还原障碍,continue

代码实现:

#include<cstdio>
#include<cstring>
using namespace std;

const int dx[5]={0,0,0,1,-1},dy[5]={0,1,-1,0,0};

int A[201][201];
int R[101];
int W,H;
int sx,sy;
int maxstep=0;
bool Is_Solved=0;

bool DFS(int x,int y,int step)
{
	if(step>=maxstep)return 0;
	int now_x=x,now_y=y;
	for(register int i=1;i<=4;i++)
	{
		x=now_x,y=now_y;
		while(x+dx[i]>=1&&y+dy[i]>=1&&x+dx[i]<=W&&y+dy[i]<=H&&A[x+dx[i]][y+dy[i]]!=1)
		{
			x+=dx[i],y+=dy[i];
			if(A[x][y]==3){Is_Solved=1;return 1;}
		}
		if(A[x+dx[i]][y+dy[i]]==1&&(now_x!=x||now_y!=y))
		{
			A[x+dx[i]][y+dy[i]]=0;
			if(DFS(x,y,step+1))return 1;//#3
			A[x+dx[i]][y+dy[i]]=1;
		}
	}
	return 0;//#4
}

signed main()
{
	register int cnt=0;
	register int i,j;
	while(scanf("%d %d",&H,&W),W||H)//#1
	{
		memset(A,0,sizeof(A));//#2
		Is_Solved=0;
		for(i=1;i<=W;i++)
			for(j=1;j<=H;j++)
			{
				scanf("%d",&A[i][j]);
				if(A[i][j]==2)
					sx=i,sy=j;
			}
		
		for(maxstep=1;maxstep<=10&&!DFS(sx,sy,0);maxstep++);
		if(Is_Solved)
			R[++cnt]=maxstep;
		else
			R[++cnt]=-1;
	}
	for(i=1;i<=cnt;i++)printf("%d\n",R[i]);
	return 0;
}

注释:
#1:个人习惯先输入行数,再输入列数。所以在输入时掉换了一下。
#2:为什么要memset呢?因为这里我的出界判断是以面前是否为障碍来判断的。若前一个数据比后一个规模小,边界外可能也是1,就造成了出界而没有排除掉的情况而WA。
#3:以经return 1了,就无需回溯了。
#4:一定要返回0!!!否则会返回一个随机的东西,导致答案错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值