OpenJudge1328:Radar Installation

/*
重要结论:
如果可以找到一个雷达同时覆盖多个区间,那么把这多个区间
按照起点坐标从小到大排序,则最后一个区间(起点最靠右的)
k的起点,就能覆盖所有区间。

证明:如果它不能覆盖某个区间x,那么它必然位于 
      1)x起点的左边,或者 2)x终点的右边
      情况1)和k的起点是最靠右的矛盾
      情况2)如果发生,则不可能找到一个点同时覆盖x和k,
      也和前提矛盾,有了这个结论,就可以只挑区间的起点
      来放置雷达了。 
贪心算法:
1)将所有的区间起点从小到大排序,并编号0-(n-1)
2)一次考察每个区间的起点,看要不要再哪里放雷达。开始,
所有区间都没被覆盖,所以目前编号最小的未被覆盖的区间的编号
firstNoConverd=0 
-----------now1
   -----now2 
     1-----------
           ---------- 
             -------------- 
                  2---------------
                              3----------

3)考察一个区间i的起点Xi的时候,要看从firstNoCovered
到区间i-1中是否存在某个区间c,没有被Xi覆盖。如果没有,
则先不急于在Xi放雷达,接着往下看。如果有,那么c的终点
肯定在Xi的左边,因此不可能用同一个雷达覆盖c和i。即能覆盖c的点,
已经不可能覆盖i和i后面的区间了。此时,为了覆盖c,
必须放一个雷达了,放在区间i-1的起点即可覆盖
所有从firstNoCovered到i-1的区间。因为当初考察i-1的起点z时候,
并没有发现z漏覆盖了从firstNoCovered到i-2之间的任何一个区间。

4)放完雷达后,将firstNoCovered改为i,再做下去。
复杂度:O(n*n) 

证明:
替换法:考虑不用贪心法获得的最佳雷达摆放方案。将其所有雷达按坐标
        从小到大排列得到X1,X2,,,用贪心法得到的雷达坐标从小到大排序则为
        y1,y2
        可证明每个Xi都可以被Yi替换,且y序列不会比x序列长,先证明x1可以用y1替换。 

*/

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
    double l,r;
}a[1111];
int t,n,d;
bool cmp(node a,node b){
    return a.l<b.l;
}
int solve(){
    int ans;
    double now;
    sort(a,a+n,cmp);
    ans=1;
    now=a[0].r;
    for(int i=1;i<n;++i){
        if(a[i].l<=now)now=min(now,a[i].r);
        else{
            ans++;
            now=a[i].r;
        }
    }
    return ans;
}
int main(){
    int x,y;
    bool flag;
    t=0;
    while(true){
        ++t;
        cin>>n>>d;
        if(n==0&&d==0)break;
        flag=true;
        for(int i=0;i<n;++i){
            cin>>x>>y;
            if(y>d)flag=false;
            else{
                a[i].l=x-sqrt(d*d-y*y);
                a[i].r=x+sqrt(d*d-y*y);
            }
        }
        if(flag)cout<<"Case "<<t<<": "<<solve()<<endl;
        else cout<<"Case "<<t<<": "<<-1<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/gz153016/article/details/81046369