HDU 1010

题目描述

在这里插入图片描述

解题思路

剪枝

剪枝策略就是在搜索过程中利用过滤条件来剪去完全不用考虑(已经判断这条路走下去得不到最优解)的搜索路径,从而避免了一些不必要的搜索,大大优化了算法求解速度,还保证了结果的正确性。
简单的说就是把不可行的一些情况剪掉,例如走迷宫时运用回溯法,遇到死胡同时回溯,造成程序运行时间长。剪枝的概念,其实就跟走迷宫避开死胡同差不多。若我们把搜索的过程看成是对一棵树的遍历,那么剪枝顾名思义,就是将树中的一些“死胡同”,不能到达我们需要的解的枝条“剪”掉,以减少搜索的时间。

奇偶剪枝

把矩阵看成如下形式:(0和1代表奇偶性) 
0 1 0 1 0 1 
1 0 1 0 1 0 
0 1 0 1 0 1 
1 0 1 0 1 0 
0 1 0 1 0 1 

从为 0 的格子走一步,必然走向为 1 的格子 。
从为 1 的格子走一步,必然走向为 0 的格子 。
即: 从 0 走向 1 必然是奇数步,从 0 走向 0 必然是偶数步。

所以 当遇到从 0 走向 0 (1 走向 1 ) 但是要求时间是奇数的
或者 从 1 走向 0 (0 走向 1 ) 但是要求时间是偶数的
都可以直接判断不可达!

比如有一地图:
S...
....
....
....
...D

要求从S点到达D点,此时,从S到D的最短距离为
 s = abs ( dx - sx ) + abs ( dy - sy )


如果地图中出现了不能经过的障碍物:
S..X
XX.X
...X
.XXX
...D

此时的最短距离 s' = s + 4
绕开障碍就会偏移原路线,但不管偏移几个点,最终都要回到原路径上
偏移的距离都是最短距离 s 加上一个偶数距离(因为一出一进)

就如同上面说的矩阵
要求你从0走到0,无论你怎么绕,永远都是最短距离 (偶数步) 加上偶数步
要求你从1走到0,永远只能是最短距离 (奇数步) 加上偶数步

结论:路径的偏移量永远为偶数。
因为最短路径步数 + 偏移量(偶数)= 某一可行解歩数
又 偶数 + 偶数 = 偶数,奇数 + 偶数 = 奇数
故 某一可行解步数的奇偶性由最短路径步数决定
即 最短路歩数和某一可行解歩数的奇偶性相同

奇偶剪枝最常用的就是在t时刻到达终点这种问题。
简而言之,就是我们当前点距终点的最短步数+我们现在走过的步数一定要与t的奇偶性相同,否则不可能在t时刻到达。
dis=t-step-abs(ex-x)-abs(ey-y);


代码

#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
int n,m,t,sx,sy,ex,ey,flag,vis[10][10];
char map[10][10];   //存图
int dx[]={0,-1,0,1},dy[]={1,0,-1,0};   //上下左右四个方向

void dfs(int x,int y,int step){
	if(flag)return ;   //剪枝,如果已经找到了就没必要再找了 
	int dis =t-step-abs(ex-x)-abs(ey-y)if ( dis < 0 || dis &1 ) return;   // 剩余步数小于最短距离或者满足奇偶剪枝条件  
	vis[x][y]=1;
	if(step==t){  
		if(map[x][y]=='D'){flag=1;return;}   //如果是终点就标记flag为1,然后退出
		else return;   //如果不是终点就直接退出
	}   
	for(int i=0;i<4;i++){
		int u=x+dx[i],v=y+dy[i];
		if(u<1||u>n||v<1||v>m||map[u][v]=='X'||vis[u][v])	continue;   //如果越界、已访问或者是障碍就跳过
		vis[u][v]=1;    //否则就标记为已访问
		dfs(u,v,step+1);  //进一步搜索
		vis[u][v]=0;   //回溯
	}	 
}

int main()
{
	while(cin>>n>>m>>t&&n&&m&&t){
		memset(map,0,sizeof map);   //每组测试都需要初始化,以免出现意外
		memset(vis,0,sizeof vis);
		flag=0;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				cin>>map[i][j];
				if(map[i][j]=='S'){sx=i;sy=j;}
				if(map[i][j]=='D'){ex=i;ey=j;}
			}
		}
		dfs(sx,sy,0);
		if(flag) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wiz1code(算法号)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值