【回溯】B030_hdu1010_Tempter of the Bone(dfs + 连通问题 (奇偶剪枝))

一、题目描述

小明做了一个很久很久的梦,醒来后他竟发现自己和朋友在一个摇摇欲坠的大棋盘上,他们必须得想尽一切办法逃离这里。

经过长时间的打探,小明发现,自己所在的棋盘格子上有个机关,上面写着“你只有一次机会,出发后t秒大门会为你敞开”,而他自己所在的棋盘是大小为 N*M 的长方形,他可以向上下左右四个方向移动(不可走有障碍点)。棋盘中有一扇门。

根据机关的提示,小明顿时明白了,他和朋友必须在第 t 秒到门口。而这一切,没有回头路!因为一旦他移动了,他刚才所在的点就会消失,并且他不能在一个点上停留超过一秒,不然格子会爆炸。

大逃亡开始了,请问小明和朋友能安全的逃出这奇怪的棋盘吗?

Input

输入多组测试数据。每个测试用例的第一行包含三个整数 N、M 和 T ( 1 < N , M < 7 ; 0 < T < 50 ),分别表示棋盘的大小和门打开的时间。接下来的N行给出棋盘布局,每一行包含M个字符。其中

  • “.”: 无障碍点
    “X”: 障碍点
    “S”: 起点
    “D”: 门

输入以 3 个 0 结束。这个测试用例不需要处理。

Output

对于每组样例输出一行。
如果小明能够安全逃出,输出 “YES” ,否则输出 “NO”。

Sample Input
4 4 5
S.X.
..X.
..XD
....
3 4 5
S.X.
..X.
...D
0 0 0

Sample Output
NO
YES

二、题解

方法一:dfs 暴搜

  • 常规 dfs,只能得 30pt。
  • 小剪枝:当 reach = true 时,不必继续搜索。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static int N, M, T;
	static int sx, sy, ex, ey;
	static char[][] grid;
	final static int[][] dir = { {0,1},{0,-1},{1,0},{-1,0} };
	static boolean[][] vis;
	static boolean reach;
	
	static boolean inArea(int x, int y) {
		return x >= 0 && x < N && y >= 0 && y < M;
	}
	static void dfs(int x, int y, int t) {
		if (grid[x][y] == 'D') {
		    reach = t == T;
			return;
		}
		if (reach) return;
		for (int k = 0; k < 4; k++) {
			int tx = x + dir[k][0];
			int ty = y + dir[k][1];
			if (!inArea(tx, ty) || grid[tx][ty] == 'X' ||  vis[tx][ty])
			    continue;
			vis[tx][ty] = true;
			dfs(tx, ty, t+1);
			vis[tx][ty] = false;
		}
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
		while (true) {
			N = sc.nextInt();
			M = sc.nextInt();
			T = sc.nextInt();
			if (N == 0 && M == 0 && T == 0)
				break;
			vis = new boolean[N][M];
			grid = new char[N][M];
			for (int i = 0; i < N; i++) {
				String s = sc.next();
				for (int j = 0; j < M; j++) {
					grid[i][j] = s.charAt(j);
					if (grid[i][j] == 'S') {
					    sx = i; sy = j;
					} else if (grid[i][j] == 'D') {
					    ex = i; ey = j;
					}
				}
			}
			vis[sx][sy] = true;
			dfs(sx, sy, 0);
			System.out.println(reach ? "YES" : "NO");
			reach = false;
		}
    }
}

可剪枝的地方:

  • 预处理剪枝:当前位置 (x, y),那么当前可走的步数则为:T-t,而两点之间最短距离,也叫曼哈顿距离则为 abs(sx-ex) + abs(sy-ey),所以当 T-t < abs(sx-ex) + abs(sy-ey)
    3 3 4
    S X X 
    . X X
    X . D     在这里n*m-obs = 3*3-5 = 4 = t,故不可达
    
  • 奇偶剪枝

复杂度分析

  • 时间复杂度: O ( 2 n ) O(2^n) ,注:回溯问题一般都不是线性复杂度。
  • 空间复杂度: O ( . . . ) O(...)

方法二:bfs

这是个错误的选择,因为 bfs 报出来的一定是最短路,而最短路不一定就是要求时间 T。


参考博客:https://blog.csdn.net/nvliba/article/details/48532709,有图无码
10赞
文字解释
测评地址:https://vijos.org/d/orina_personal/p/5c4f2bf0f41362860e389f83

发布了714 篇原创文章 · 获赞 199 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/105595909