POJ1328-Radar Installation

全解题报告索引目录 -> 【北大ACM – POJ试题分类

转载请注明出处:http://exp-blog.com

-------------------------------------------------------------------------

 

 

转化问题,使用贪心算法求解

 

 

/*
	Author:     Exp
	Date:       2017-12-06
	Code:       POJ 1328
	Problem:    Radar Installation
	URL:		http://poj.org/problem?id=1328
*/

/*
	题意分析:
	  给定一个直角坐标系,定义x轴为海岸线,海岸线上方是海,下方是陆地.
	  在海域零星分布一些海岛, 需要要在海岸线上安装若干个雷达覆盖这些海岛,
	  每个雷达的覆盖半径都是相同且固定的.

	  现在给定所有海岛的坐标(x,y), 以及雷达的覆盖半径d,
	  问可以覆盖所有海岛的最小雷达数.


	解题思路:
	  首先可以明确的是:只要存在任意一个海岛位置超出雷达最大覆盖半径(即y>d),则无解.

	  在所有海岛的 y<=d 的前提下去思考此问题,
	  那么此问题的切入点是需要知道【一个雷达要覆盖一个海岛,其可以安装范围是多少】

	  以海岛坐标(x,y)为圆心,用雷达覆盖半径d画圆,根据前提条件可知,
	  这个圆与x轴必定存在最少1个(y=d)、最多2个交点(y<d).

	  可以认为1个交点是2个交点重合的特殊情况,那么这2个交点在x轴上构成的线性区间,
	  可以看作海岛的被覆盖范围在x轴上的投影 (由此就可以把二维的几何问题转化成一维几何问题)

	  按照所有海岛的x轴坐标,从小到大依次计算每个海岛在x轴上的投影区间(投影可能存在重叠),
	  同时把每个雷达抽象成1个点,那么此问题就转化成:

	  【已知x轴上若干个区间(可能存在交集),现在要往这些区间内放若干个点,
	  问怎样放置这些点,使得每个区间内至少存在一个点,且所放置的点的总量尽可能最少】
	
	  
	  可使用贪心算法求解:
	    根据每个区间的左端点坐标对所有区间从左到右排序:
		① 在左起第一个区间A 的右端点 A.R 放置一个点,总放置点数 P+1 
		② 若下一个区间B 的左端点 B.L > A.R, 
		    说明 区间A 与 区间B 无交集,此时在区间B 的右端点 B.R 放置一个点,总放置点数 P+1 

		   否则说明 区间A 与 区间B 相交, 此时进一步判断,若 B.R < A.R,
			说明 区间B 在 区间A 的内部,此时把原本放置在 A.R 的点移动到 B.R(确保区间B有一个点),总放置点数不变

		③ 重复这个过程直到所有区间被遍历完成
*/


#include <math.h>
#include <algorithm>
#include <iostream>
using namespace std;


// 海岛在x轴上的投影区间
struct Interval {
	double left;	// 左端点在x轴上的坐标
	double right;	// 右端点在x轴上的坐标
};


/* 
 * 求解问题:在每个区间内至少放置一个点,使得放置的点的总量最少
 * @param intervals 区间集合
 * @param size 区间个数
 * return 最小的放置点数
 */
int solve(Interval* intervals, int size);


/* 
 * 比较两个区间的大小(用于排序)
 *  左端点越小的区间,该区间的顺次越小
 * @param a 区间a
 * @param b 区间b
 * return a.left <= b.left
 */
bool compare(Interval a, Interval b);


int main(void) {
	int island, radius, testCase = 0;
	while((cin >> island >> radius) && island && radius) {
		const double R2 = radius * radius;	// 半径平方
		Interval* intervals = new Interval[island];

		bool isSolvable = true;
		for(int i = 0; i < island; i++) {
			double x, y;
			cin >> x >> y;
			if(y > radius) {	// 存在海岛不在雷达的最大影响范围,无解
				isSolvable = false;
			}

			double offset = sqrt(R2 - y * y);	// 勾股定理
			intervals[i].left = x - offset;
			intervals[i].right = x + offset;
		}

		int minRadar = (isSolvable ? solve(intervals, island) : -1);
		cout << "Case " << ++testCase << ": " << minRadar << endl;
		delete[] intervals;
	}
	return 0;
}


int solve(Interval* intervals, int size) {
	sort(intervals, intervals + size, compare);

	int minPoint = 1;
	double right = intervals[0].right;
	for(int i = 1; i < size; i++) {

		// 区间i-1 与 区间i 无交集
		if(intervals[i].left > right) {
			minPoint++;
			right = intervals[i].right;

		// 区间i-1 在 区间i 内部
		} else if(intervals[i].right < right) {
			right = intervals[i].right;

		} else {
			// Undo: 区间i-1 与 区间i 相交 
		}
	}
	return minPoint;
}


bool compare(Interval a, Interval b) {
	return a.left <= b.left;
}

 

 

 

 

 

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
根据您的问题,我理解您想了解POJ1328问题的Java解决方案。POJ1328是一个经典的问题,也被称为"雷达安装"问题,它涉及到在一个二维平面上安装雷达以覆盖所有岛屿的最小雷达数量。以下是一个Java解决方案的示例代码: ```java import java.util.Arrays; import java.util.Comparator; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int caseNum = 1; while (true) { int n = scanner.nextInt(); if (n == 0) { break; } Island[] islands = new Island[n]; for (int i = 0; i < n; i++) { int x = scanner.nextInt(); int y = scanner.nextInt(); islands[i] = new Island(x, y); } int radarNum = getRadarNum(islands); System.out.println("Case " + caseNum + ": " + radarNum); caseNum++; } } private static int getRadarNum(Island[] islands) { Arrays.sort(islands, Comparator.comparingInt(Island::getRight)); int radarNum = 1; int rightMost = islands[0].getRight(); for (int i = 1; i < islands.length; i++) { if (islands[i].getLeft() > rightMost) { radarNum++; rightMost = islands[i].getRight(); } else { rightMost = Math.min(rightMost, islands[i].getRight()); } } return radarNum; } static class Island { private int left; private int right; public Island(int left, int right) { this.left = left; this.right = right; } public int getLeft() { return left; } public int getRight() { return right; } } } ``` 这段代码通过输入岛屿的坐标,计算出需要安装的最小雷达数量,并输出结果。它使用了排序和贪心算法的思想来解决问题。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值