HDU 1010 Tempter of the Bone (dfs+奇偶剪枝+路径剪枝)

 原题链接

小狗在一个古老的迷宫中发现了一块骨头,这让他很着迷。然而,当他拿起它时,迷宫开始摇晃,小狗可以感觉到地面下沉。他意识到骨头是一个陷阱,他拼命想要摆脱这个迷宫。

迷宫是一个大小为N×M的矩形。迷宫中有一扇门。在开始时,门被关闭,它将在第T秒开启一小段时间(不到1秒)。因此,小狗必须在第T秒才到达门口。在每一秒中,他可以将一个块移动到上,下,左和右相邻块之一。一旦他进入一个区块,这个区块的地面将开始下沉并在下一秒消失。他不能在一个街区停留一秒以上,也不能进入一个被访问的街区。这只可怜的小狗能活下来吗?请帮帮他。

 

输入包含多个测试用例。每个测试用例的第一行包含三个整数N,M和T(1 <N,M <7; 0 <T <50),分别表示迷宫的大小和门打开的时间。 。接下来的N行给出迷宫布局,每行包含M个字符。角色是下列之一:

'X':一块墙,小狗不能进入; 
'S':小狗的起点; 
'D':门; 或
'.':空块。

输入以三个0结束。不处理此测试用例。

 

这个写的不错:1010 temp of the bone 解题报告

 

N 行 M 列 T 时间,看这个doggie是否能在第T秒刚好到达门。S是doggie的起始位置,D是门的位置。

一开始我对这个时间T有点不理解,拿题目中例2来说S走4步在D的前一个位置,再走一步到达D,题目是要在5秒刚好在D,而不是所谓的在时间T内到达就行了。

这道题里涉及一些剪枝问题,如果不剪枝就会超时。(我们来把这道题的迷宫想象成一块一块的格子)。

①n*m-wall<=t . n*m代表总共的格子,n*m-wall代表能走的格子数目,t是时间,n*m-wall<=t也就是可以走的格子走完了时间T都没有到,肯定不能到达D。至于为什么有=,看的一个大佬写的一个例子:

3 3 4

S X X 

. X X

X . D     在这里n*m-wall=3*3-5=4=t,这里是不能到达的。

②奇偶剪枝

因为两点之间直线最短,所以由S到达D的最短路径就是abs(sx-dx)+abs(sy-dy),可以把t理解为题目要你走的总步数,t-step就代表你任意走的总步数,因为abs(sx-dx)+abs(sy-dy)已经是最短的步数了,你走的一定不可能比它更短,所以t-step肯定是要>=最短步数的。所以当t-step<abs(sx-dx)+abs(sy-dy)的时候,我们就给它剪出去。(注意sx,sy,step都是在变化的)

还有t-step-abs(sx-dx)-abs(sy-dy)必须是偶数,如果是奇数就不能到达D,给个例子大家看看吧 

3行4列    最短距离是5。红色箭头代表随意走的路线,一共9步,9-5=4为偶数,刚好到达D,如果为奇数,那最后一步到达的肯定是D的周围而不能刚好到达D。

一开始不会剪枝,看了博客,学会了奇偶剪枝+路径剪枝,还有别忘记标记起点的vis[x1][y1]

import java.util.Scanner;

public class hdu1010 {

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while(in.hasNext()) {
			n = in.nextInt();
			m = in.nextInt();
			T = in.nextInt();
			if(n==0)
				break;
			vis = new boolean[n][m];
			ch = new char[n][m];
			flag = false;
			wall = 0;
			x1=y1=-1;
			for(int i=0;i<n;i++)
				ch[i] = in.next().toCharArray();
			for(int i=0;i<n;i++)
				for(int j=0;j<m;j++)
					if(ch[i][j]=='S') {
						x1 = i;
						y1 = j;
					}else if(ch[i][j]=='D') {
						x2 = i;
						y2 = j;
					}else if(ch[i][j]=='X')
						wall++;
			
			if(n*m-wall<=T) {//路径剪枝
				System.out.println("NO");
				continue;
			}
			vis[x1][y1] = true;
			dfs(x1,y1,0);
			if(flag)
				System.out.println("YES");
			else
				System.out.println("NO");
		}
	}
	
	
	static int n,m,T,x1,y1,x2,y2,wall;
	static boolean[][] vis;
	static char[][] ch;
	static boolean flag;
	static int[] dx = new int[] {1,0,-1,0};
	static int[] dy = new int[] {0,1,0,-1};

	
	static void dfs(int x,int y,int t) {
		if(ch[x][y]=='D') {
			if(t==T)
				flag = true;
			return;
		}
		
		int p = T - t - (Math.abs(x-x2)+Math.abs(y-y2));//剩余步-最短路径判断
		if(p<0 || p%2==1)//奇偶剪枝 p只能为偶数
			return;
		
		for(int i=0;i<4;i++)
			if(ok(x+dx[i],y+dy[i])) {
				vis[x+dx[i]][y+dy[i]] = true;
				dfs(x+dx[i],y+dy[i],t+1);
				vis[x+dx[i]][y+dy[i]] = false;
				if(flag)//找到答案就结束所有在搜索的路径
					return;
			}
	}
	
	static boolean ok(int x,int y) {
		return x>=0 && x<n && y>=0 && y<m && ch[x][y]!='X' && !vis[x][y];
	}

}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值