POJ 1328 Radar Installation(贪心)

来源:互联网 发布:moodle网络课程平台 编辑:程序博客网 时间:2024/06/03 17:52

Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d. 

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates. 
 
Figure A Sample Input of Radar Installations


Input
The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases. 

The input is terminated by a line containing pair of zeros 
Output
For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. "-1" installation means no solution for that case.
Sample Input
3 21 2-3 12 11 20 20 0
Sample Output
Case 1: 2Case 2: 1

题意:你要在海岸线上布置一些相同的雷达(x轴)(雷达监测范围是一个半径为R的圆),以监测在大海中的一些小岛(y轴正半轴),给出小岛的坐标x,y,以及雷达的半径。问最少需要布置多少雷达

题解:

这道题有点需要认真思考一下,可以这样生成思路,想象一个半圆,从x负半轴的无穷远平移过来,直到它的左边的1/4圆弧与某个节点相重合,删掉被半圆包含的点,如此

重复,直到所有的圆都被删除完。可以这样证明这个贪心策略的正确性:对于会与左边的1/4圆弧与相重合的节点,如果不是在重合的时候最优,那么就是在左边或右边最优

先考虑右边,如果是右边的话,这个节点就不会被圆包含,那么就需要两个圆,如果在左边,覆盖范围不如刚好重合的时候,故此,刚好重合时最优。

代码实现如果按照上述思路来说很困难,需要转换一下,在找那个与某个刚好重合的圆的时候,不可能算圆系方程吧?我们是以小岛为圆,以半径R作圆,与x轴的右交点就是

那个圆的圆心了,这个可以有勾股定理算,我们也并不需要如此麻烦的去删除节点,在以小岛为圆的时候,我们存储下每个小岛与x轴的左右交点,按右端点排序,那么对于两

个小岛来说,如果i小岛的右交点比j小岛的左交点大(i<j),那么根据几何意义(画个图就可以了,比较显然),j小岛是可以被i小岛的圆所包含的

代码:

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<cstdlib>#include<algorithm>const int MAXN=1005;using namespace std;struct node{double x,y;}island[MAXN];struct Node{double left,right;}circle[MAXN];int n;double d,esp=0.000001;double dist(node a,double b){    return sqrt(b*b-a.y*a.y);}bool cmp(Node a,Node b){    return a.right<b.right;}int main(){    int cas=0;    while(1)    {        int ans=0; bool flag=0;        scanf("%d%lf",&n,&d);        if(!n&&!d) return 0;        for(int i=1;i<=n;i++)        {            scanf("%lf",&island[i].x);            scanf("%lf",&island[i].y);            if(island[i].y>d) flag=1;            if(island[i].y<0) flag=1;        }        printf("Case %d: ",++cas);        if(flag)        {            putchar('-'); putchar('1'); putchar(10);            continue;        }        for(int i=1;i<=n;i++)        {            circle[i].left =island[i].x-dist(island[i],d);            circle[i].right=island[i].x+dist(island[i],d);        }        sort(circle+1,circle+n+1,cmp);        for(int i=1;i<=n;)        {            /*            int j; ans++;            for(j=i+1;j<=n&&circle[i].right>=circle[j].left;j++);            i=j;*/            double last=circle[i].right;            ans++;i++; while(i<=n&&circle[i].left<=last)i++;        }        printf("%d\n",ans);    }}