hihoCoder太阁最新面经算法竞赛题解(3)

题目来源:

    HihoCoder1307

题目要求:

    作为某国的精英特工,你接到了一项任务,驾驶一辆吉普穿越布满监测雷达的禁区。为了简化题目,我们可以把禁区想象为一个左下角是(0, 0)右上角是(W,H)的长方形区域。区域中一共有N座雷达,其中第i座的坐标是(Xi,Yi),监测范围是半径为Ri的圆形区域。所有在圆内和圆上的运载工具都会被监测到。

你的目标是从左到右穿越禁区。你可以选择线段(0, 0)-(0, H)上任意一点作为起点,线段(W, 0)-(W, H)上任意一点作为终点。在禁区内你可以沿任意路线行驶,只要保持始终在禁区内并且没有被雷达监测到。
    
给出禁区内的雷达部署方案,你需要判断是否存在满足条件的行驶路线。

解答:

   本题是一道考察搜索算法的题目。首先需要了解的是,多个雷达的监控区域将会有重叠的现象,多个具有重叠监控区域的雷达可以构成一片连续的监控区域,如下图所示:

    
    图中红色虚框即为多个雷达构成的连续区域,寻找连续区域的过程可以通过搜索来实现,深度和广度优先搜索均可。
    得到连续区域后,通过画图可以看出:显然,存在可以躲过所有监控区域穿过禁区的路线的充要条件是所有的连续区域在y轴方向没有完全覆盖区间[0,H]。例如,上面示意图中第二个连续区域在y轴方向上完全覆盖了区间[0,H],因此,上图的情况是无解的,即不存在可以躲过所有雷达监控穿越进去的路线。
    在搜索过程中记录连续区域y坐标的最大值和最小值来得到每个连续区域的区域上界和区域下界,如果所有的连续区域满足:区域上界不小于H,或区域下界大于0,则存在有效的路线;如果存在一个连续区域满足:区域上界不小于H,并且区域下界不大于0,则不存在有效的路线。
    以上为本题解法,解答时需要注意数据溢出。

输入输出格式:

    输入:

输入包含多组数据。

1行是一个整数T表示以下有T组数据 (1≤T≤10)。

每组数据的第1行:三个整数WHN(0≤ W,H ≤ 10000001≤N≤1000)。

每组数据的第2 - N+1行:每行三个整数Xi,Yi,Ri 
(0≤Xi≤W0≤Yi≤H1≤Ri≤1000000)。

输出:
     对于每组数据输出"YES"或者"NO"表示是否有满足条件的行驶路线。 

程序代码:

package hihocoder;

import java.util.Scanner;

/**
 * This is the ACM problem solving program for hihoCoder 1307.
 * 
 * @version 2017-04-26
 * @author Zhang Yufei.
 */
public class HihoCoder1307 {
	private static class Radar {
		int x;
		int y;
		int r;
		boolean visited;
	}

	/**
	 * Input data.
	 */
	@SuppressWarnings("unused")
	private static int T, W, H, N;

	/**
	 * Radar list.
	 */
	private static Radar[] radars;

	/**
	 * For input.
	 */
	private static Scanner scan;

	/**
	 * Record the range.
	 */
	private static int min, max;

	/**
	 * The main program.
	 * 
	 * @param args
	 *            The command-line parameters list.
	 */
	public static void main(String[] args) {
		scan = new Scanner(System.in);

		T = scan.nextInt();

		for (int i = 0; i < T; i++) {
			function();
		}

		scan.close();
	}

	/**
	 * Deals with one test case.
	 */
	private static void function() {
		W = scan.nextInt();
		H = scan.nextInt();
		N = scan.nextInt();

		radars = new Radar[N];

		for (int i = 0; i < N; i++) {
			radars[i] = new Radar();
			radars[i].x = scan.nextInt();
			radars[i].y = scan.nextInt();
			radars[i].r = scan.nextInt();
			radars[i].visited = false;
		}

		for (int i = 0; i < N; i++) {
			if (!radars[i].visited) {
				max = Integer.MIN_VALUE;
				min = Integer.MAX_VALUE;
				dfs(i);
				if(min <= 0 && max >= H) {
					System.out.println("NO");
					return;
				}
			}
		}
		
		System.out.println("YES");
	}

	/**
	 * Use DFS to find the answer of this problem.
	 * 
	 * @param radar
	 *            The current radar to search;
	 */
	private static void dfs(int index) {
		Radar radar = radars[index];
		radar.visited = true;

		if (max < radar.y + radar.r) {
			max = radar.y + radar.r;
		}

		if (min > radar.y - radar.r) {
			min = radar.y - radar.r;
		}

		for (int j = 0; j < N; j++) {
			if (!radars[j].visited) {
				Radar rj = radars[j];
				long x1 = (long) radar.x;
				long x2 = (long) rj.x;
				long y1 = (long) radar.y;
				long y2 = (long) rj.y;
				long r1 = (long) radar.r;
				long r2 = (long) rj.r;
				if (Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) <= 
						Math.pow(r1 + r2, 2)) {
					dfs(j);
				}
			}
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值