区域覆盖问题

来源:互联网 发布:陕西广电网络集团待遇 编辑:程序博客网 时间:2024/05/22 17:01

POJ1328是一道经典的贪心算法例题。题目大意是假设海岸线是一条无限延伸的直线。陆地在海岸线的一侧,而海洋在另一侧。每一个小的岛屿是海洋上的一个点。雷达
坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。对于每个小岛
,我们可以计算出一个雷达所在位置的区间。问题转化为如何用尽可能少的点覆盖这些区间。先将所有区间按照左端点大小排序,初始时需要一个点。如果两个区间相交而不重合,我们什么都不需要做;如果一个区间完全包含于另外一个区间,我们需要更新区间的右端点;如果两个区间不相交,我们需要增加点并更新右端点。




贪心具体思路:


图中ABCD为海岛的位置。假设本题半径为2(符合坐标系),那么A点坐标为(1,1)以此类推。

首先以A为圆心,r为半径做圆,交x轴与E1(右)点,做出如图中绿色虚线圆。然后以E1为圆心,半径为r做圆。看此时下一点(B)是否在该圆中。

存储图中红色圆与X轴的交点。先排序,但排序的准则是按红色圆与x轴左交点的先后顺序。

如图,如果B点圆(且如此称呼)的左交点(J1点)在A点圆右交点(E1)左侧,那么B点一定涵盖在A点圆内部。再如图,如果D点圆的左交点(图中未标示)在A点圆的右交点(未标示)右,则D点不在A点圆中。


题目要求

输入
输入由几个测试用例组成。每个案例的第一行包含两个整数n(1 <= n <= 1000)和d
,其中n是海中的岛屿数,d是雷达装置的覆盖距离。其后是n行,每行包含表示每个岛
的位置坐标的两个整数。接下来是一个空白行,以分开案例。
输入端由包含零对的行终止

输出:
对于每个测试用例,输出一行包括测试用例编号,然后是所需的最少数量的雷达安装。
“-1”安装意味着没有解决办法。
样品输入
3 2
1 2
-3 1
2 1


1 2
0 2


0 0  //退出
样品输出
情况1:2
情况2:1

代码及注释:(注释较多)可帮助理解

#include <iostream>#include <algorithm>#include <cmath>using namespace std;struct Between{double left;double right;}between[1001];bool cmp( Between a,  Between b){return a.left < b.left;//由小到大排序}int main(){int n, d;//n表示n个小岛 d表示雷达探测半径 int sw;//sw作为边界的判断。如果小岛到海岸的距离大于雷达的探测距离,则雷达不可能检测到小岛int re, count = 1;//count 代表第几个例子int x, y;//x,y 代表的是小岛的坐标double pre;//先前的点//雷达可以设置在河岸区间的任何一个地方。这样都能探测到当前的小岛//若雷达设置在起始岛的右边界的话,就能保证留给后续岛的覆盖空间是最大的。while (1){cin >> n >>d;if (n == 0 && d == 0)break;//输入 0 0 时退出程序sw = 1;//设置检测条件for (int i =0;i<n;i++){cin >> x >> y;if (d >= y&&sw == 1) //小岛到岸边的距离为y。雷达探测距离d需要大于y{between[i].left = x - sqrt((double)d*d - (double)y*y);between[i].right = x + sqrt((double)d*d - (double)y*y);}else{sw = 0;}}if (sw == 0){cout << "Case" << count++ << " : " << -1 << endl;//若该小岛不能探测到的话,返回-1.continue;}sort(between, between + n, cmp);//按照到岸边的左边界由小到大进行排列re = 1;//设置雷达的个数pre = between[0].right;//第一个岛的右边界for (int i = 1; i < n; i++){if (between[i].left > pre)//如果其它小岛的左边界大于现在岛的右边界,则雷达不能同时 //覆盖这两个岛。需要增加雷达个数{re++;pre = between[i].right;//并且,当前的边界换成新岛的右界}else{if (between[i].right<pre)//如果新岛的右界小于旧岛的右界,则需要把右界收缩。//目的是为了同时覆盖当前两个岛。//雷达边界换为新岛的右界{pre = between[i].right;}}//还有一种情况是新岛的左界小于现在的右界,并且新岛的右界大于现在的右界 //可以肯定的是当前设置的雷达能覆盖到新的岛。因此这个岛对安排雷达不产生额外的影响。 //因为雷达设置在起始岛的右边界的话,就能保证留给后续岛的覆盖空间是最大的。 //这样就满足了贪心算法的子问题最优化的条件}cout << "Case" << count++ << " : " << re << endl;}return 0;}


 

原创粉丝点击