hdu1010 Tempter of the Bone

http://acm.hdu.edu.cn/showproblem.php?pid=1010

题意:本体的意思是必须在规定的时间内到达指定的地点,不可以多于也不可以少于。

思路就是搜索,但是搜索的话直接暴力肯定会t,所以这里必须要剪枝。

剪枝的方法是奇偶剪枝。

奇偶剪枝是数据结构的搜索中,剪枝的一种特殊小技巧。
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s
       
|
       
|
       
|
       
+
e
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
s
 
 
+
 
|
+
     
|
       
+
e
如图,为一般情况下非 最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证);

2结论编辑

推广之,若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;
返回,false;
反之亦反。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
int a[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
char map[8][8];
int v[8][8],tt,m,n,ex,ey,flag;
void dfs(int x,int y,int t)
{	
		int i,j;
		if(x==ex&&y==ey)//注意这里 不能使用map[x][y]==D' 具体看下面解释
		{
			if(t==0)flag=1;
			return;
		}
		if(flag==1)
			return;
		int tmp;
		tmp=t-abs(x-ex)-abs(y-ey);
		if(tmp<0||tmp%2!=0)
			return;
	//	printf("%d %d\n",x,y);
		for(i=0;i<4;i++)
		{
			int xx,yy;
			xx=x+a[i][0];
			yy=y+a[i][1];
			if(map[xx][yy]!='X'&&v[xx][yy]==0&&xx>=0&&xx<n&&yy>=0&&yy<m)
			{
				v[xx][yy]=1;
				dfs(xx,yy,t-1);
				v[xx][yy]=0;
			}
		}
}
int main()
{
	int i,j,x,y,num;
	while(scanf("%d%d%d",&n,&m,&tt)!=EOF)
	{
		if(n==0&&m==0&&tt==0)
			break;
		num=0;
		memset(v,0,sizeof(v));
		flag=0;
	//	cout<<n<<m<<tt<<endl;
		for(i=0;i<n;i++)
		{
			for(j=0;j<m;j++)
			{
				cin>>map[i][j];
				if(map[i][j]=='S')
				{
					x=i;
					y=j;
				}
				if(map[i][j]=='D')
				{
					ex=i;
					ey=j;
				}
				if(map[i][j]=='X')
					num++;
			}
		}
		if(n*m-num<tt)
		{
			printf("NO\n");
			continue;
		}
		v[x][y]=1;
		dfs(x,y,tt);
		if(flag==0)
		{
			printf("NO\n");
			continue;
		}
		if(flag)
			printf("YES\n");
	}
	return 0;
}


if(di>=0&&di<n&&dj>=0&&dj<m&&map[di][dj]!='X')
{
	map[di][dj]='X';
	dfs(di,dj,cnt+1);
	map[di][dj]='.';
}

在进行dfs的时候,你首先将map[di][dj]置为了'X',在dfs结束之后再将其还原为'.'。但是此处的map[di][dj]有可能原本是'D'而不是'.',这样一来就会导致map中原本是'D'的元素变成了'.',用if(map[x][y]=='D')作为判断条件也就找不到出口了。

你可以试一试这组样例:
2 2 3
S.
D.
具体情况调试一下就清楚了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值