HDOJ 1010 DFS+剪枝

本文深入解析了HDU 1010问题的解决方案,利用深度优先搜索(DFS)结合奇偶剪枝技巧,有效地解决了在指定时间内到达目标点的问题。文章详细介绍了奇偶剪枝的概念及其应用,通过实例展示了如何判断路径的可行性,以及如何优化搜索过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1010
一开始做这道题的时候想的是BFS,但是一直WA,看好题目才知道是要在指定的时间内正好到此处,则利用DFS+奇偶剪枝来进行解题:
奇偶剪枝:https://baike.sogou.com/v72712602.htm?fromTitle=奇偶剪枝
在没有障碍物的一个矩形中,一个点到另外一个点之间的最短距离为:min=Math.abs(sx-dx)+Math.abs(sy-dy)为其两点之间的坐标的差。
如:
S 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 D
其最短路径为:min=9;
当头节点和尾节点不变,在原来的基础上加上一些阻碍
S 1 1 1 X X
X X X 1 X X
1 1 1 1 X X
1 X X X X X
1 1 1 1 1 D
X为障碍,则其最短路径为:minX=15;

则minX=min+6;
不管图是怎么样的,只要有通路对他们进行连接,则他们之间的差值都为一个偶数,这个为结论。
则奇偶剪枝就是把一些已经没有必要的枝条给减掉,不用再继续执行下去。
该剪掉的枝条:
设置:min为其没有阻碍时的最小路径; step为其从起点开始走,走到第几步的路径;minX为其实质走的路径。
1:首先判断可走的路径的长度是否满足要走的路数,如果不满足,剪掉(.的数目是否满足要走的路数)如果不满足直接输出NO
2:判断起点坐标和终点坐标之间的最短距离min是否比给出的路径小,如果比其大,则不满足,输出NO
3:判断奇偶性质,(minStep+step-min)%2==0判断是否为偶数,如果不是偶数的话则剪去,其中minStep的值为当前走到的坐标距离终点之间的的最短路径。
4:当step+minStep的值大于给出的路径长度,则表示再继续走下去也没有用了,因为剩下的最短路径都到不了,就别想到了,则剪掉。
下面为AC代码:

public class Pid1010 {
	static int row;
	static int colum;
	static int fin;
	static int sx,sy,dx,dy;
	static int[][] dex= {{1,0},{0,1},{-1,0},{0,-1}};
	static char[][] data;
	static boolean[][] marked;
	static int ant;
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while(sc.hasNext()) {
			row = sc.nextInt();
			colum = sc.nextInt();
			fin = sc.nextInt();
			sc.nextLine();
			if(row==0&&colum==0&&fin==0)
				break;
			marked = new boolean[row][colum];
			data = new char[row][colum];
			int count=0;
			for(int i=0;i<row;i++) {
				String str = sc.next();
				data[i]=str.toCharArray();//输入数据
				for(int j=0;j<colum;j++) {
					if(data[i][j]=='D'||data[i][j]=='d') {
						dx=i;
						dy=j;
					}else if(data[i][j]=='.')
							count++;
					else {
						if(data[i][j]=='S'||data[i][j]=='s') {
							sx=i;
							sy=j;
						}
					}			
				}
			}
			ant = Math.abs(sx-dx)+Math.abs(sy-dy);//起点和终点之间的最短路径
			marked[sx][sy]=true;
			if(count+1<fin||ant>fin)//剪枝条件,.的数目满足不了给出的路径,最短路劲ant比需要走的路径还要大,剪掉
				System.out.println("NO");
			else {
				if(dfs(sx,sy,0))//分别为起点的横坐标,起点的纵坐标,和步数。
					System.out.println("YES");
				else System.out.println("NO");
			}
		}
	}
	private static boolean dfs(int tempx, int tempy, int step) {
		if((data[tempx][tempy]=='D'||data[tempx][tempy]=='d')&&step==fin) {//当步数正好为需要的路径长度的时候,则满足
			return true;
		}
		for(int i=0;i<4;i++) {//四个方向进行判断
			boolean temp = true;
			int a = tempx+dex[i][0];
			int b = tempy+dex[i][1];
			if(a<0||a>=row||b<0||b>=colum||marked[a][b]||data[a][b]=='X'||data[a][b]=='x')
				continue;
			int minStep = Math.abs(tempx-dx)+Math.abs(tempy-dy);//当前点距离终点之间的最短路径
			if(minStep>fin-step||(step+minStep-ant)%2!=0) //当前点距离终点的最短路径比需要走的路径长度减去已经走了步数还要长则剪去,奇偶性,不为偶数的话则剪去。
				temp=false;
			if(!temp)
				continue;
			if((data[a][b]=='d'||data[a][b]=='D')&&step!=fin-1)//如果D这个坐标被打true了的话则不会访问了
				continue;
			marked[a][b]=true;
			if(dfs(a,b,step+1))return true;
			marked[a][b]=false;
		}
		return false;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值