poj 1328: Radar Installation (贪心)

传送门:http://poj.org/problem?id=1328
题目大意:给定一条海岸线即x轴,上方为海,下方为陆地。在海中有n个小岛,希望在海岸线上装雷达,每个雷达辐射区域均为半径为d的圆,问至少要装多少个雷达才能使所有的岛屿都在雷达辐射区域内。

先上代码

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

struct island
{
	double leftEdge;//记录在x轴上安装雷达可以辐射到岛时x最左边位置
	double rightEdge;//记录在x轴上安装雷达可以辐射到岛的x最右边位置
	island(double l = 0, double r = 0)
	{
		leftEdge = l;
		rightEdge = r;
	}
};

bool compare(island a, island b)
{
	return(a.leftEdge < b.leftEdge);
}

int main()
{
	int n, d, t = 1;
	cin >> n >> d;
	while (d != 0)
	{
		island islands[1000];
		int numofRadar = 0;//记录最小雷达数量
		for (int i = 0; i < n; i++)
			//输入雷达位置
		{
			int xPos, yPos;
			cin >> xPos;
			cin >> yPos;
			if (yPos > d)numofRadar = -1;
			double tmpLength = sqrt(abs((double)d * d - yPos * yPos));
			islands[i].leftEdge = xPos - tmpLength;
			islands[i].rightEdge = xPos + tmpLength;
		}
		sort(islands, islands + n, compare);
		if (numofRadar != -1)
		{
			numofRadar = 1;
		}
		double leftEdge = islands[0].leftEdge;
		double rightEdge = islands[0].rightEdge;
		for (int i = 1; i < n; i++)
		{
			if (islands[i].leftEdge <= rightEdge)//两个范围有相交
			{
				//cout << "两个范围有相交"<<endl;
				leftEdge = max(leftEdge, islands[i].leftEdge);
				rightEdge = min(rightEdge, islands[i].rightEdge);
				//此时雷达次数不需要增加,但是左右边界需要变化
			}
			else
				//两个范围没有相交,需要重新加雷达
			{
				if (numofRadar != -1)
				{
					numofRadar++;//雷达数量++
				}
				leftEdge = islands[i].leftEdge;
				rightEdge = islands[i].rightEdge;
			}
		}
		cout << "Case " << t << ": " << numofRadar << endl;
		cin >> n >> d;
		t++;
	}
	return 0;
}

解题思路:
使用贪心算法,与活动选择问题类似。

如果出现有小岛的y>d的情况即没有雷达能覆盖到该小岛的情况,将flag设置为1,最后输出-1。

下面只考虑每个小岛y均小于d的情况:
以每个小岛为圆心做一个半径为d的圆,会与x轴相交与2点,leftEdge和rightEdge可以知道所有安装在这个区间内的雷达均可以覆盖到该岛。以下简称小岛范围和小岛左右边界

创建一个结构体数组记录以每个小岛左右边界,然后按照每个小岛的左边界将海岛进行升序排序。

定义leftEdge和rightEdge参数,用来记录当前最后一个雷达可以安装的范围。(由于小岛按照左边界排序,如果从左到右遍历,某个小岛范围已经不能与之前安装雷达有重叠,则后面的小岛也不会与之前安装雷达有重叠,所以每次只用记录最后一个新安雷达能安装的范围即可)如果新加入的海岛雷达覆盖范围有交集,则不需要再加入新的雷达,如果没有交集则需装新雷达。

算法步骤
1.先选左边界在最左边的岛,此时将雷达数量设为1,这个雷达可安装的位置为当前岛的左右边界之间。将leftEdge和rightEdge赋值。
double leftEdge = islands[0].leftEdge;
double rightEdge = islands[0].rightEdge;
2.新加入一个岛,会出现两种情况
(1)如果该岛的islands[i].rightEdge<=rightEdge则不需加新雷达,只用修改当前最后一个雷达应该安装的范围即可,这个雷达应该安装在新的范围与之前雷达安装范围的交集中。更新当前最后一个雷达可安装位置
leftEdge = max(leftEdge, islands[i].leftEdge);
rightEdge = min(rightEdge, islands[i].rightEdge)
(2)如果该岛的islands[i].rightEdge>rightEdge则需加新雷达,这个雷达可安装范围应该与该小岛的范围相同。更新当前最后一个雷达可安装位置,并将雷达数量+1。
leftEdge = islands[i].leftEdge;
rightEdge = islands[i].rightEdge;

避雷!
1.sort函数要求严格,compare函数中当两者相等的时候必须返回时false否则会报错。
2.sqrt函数有多种重载形式,如果需要在函数中转化数据类型,sqrt((double)d * d - yPos * yPos),虽然VS中编译没有问题但是poj会报compile error。
3.如果poj中出现Presentation Error,说明代码基本是对的,只是在输出中多了或者少了回车或空格之类的问题。

一开始的时候思路有点混乱,将小岛按x坐标升序排序后再从左到右遍历小岛来看是否增加雷达,这种做法不可取的原因是如果有可能存在第t个小岛的y非常高,导致其范围与已存在的雷达可装范围无重叠导致需要新增雷达,但可能后面存在某个y非常小的小岛能被之前安装的雷达覆盖到,所以导致错误。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值