1. 程式人生 > 其它 >POJ-1328 Radar Installation題解

POJ-1328 Radar Installation題解

Radar Installation(貪心)

題意

  假設在一條無限延伸的\(x\)軸上方存在\(n\)個點,現問是否能用多個在圓心在\(x\)軸上,半徑為\(d\)的圓包含所有的點,若可以,輸出最少的使用個數,不行則輸出\(-1\)

思路

  先考慮不行的情況,只要點的離\(x\)軸的高度超過圓的半徑\(d\),就不可能用圓來覆蓋。
  接下來,我們可以先想一下兩個點的情況,什麼時候需要增加新的圓?設兩個點分別為\(A、B\),並假設\(B\)\(A\)的右側。能圈住\(A\)點並且向右覆蓋範圍最大的是當\(A\)點在圓上,此時圓心\(X_A\)的位置最靠右,只要\(B\)離圓心的距離大於半徑,並且能圈住\(B\)

並向右覆蓋範圍最大的圓的圓心\(X_B\)在點\(X_A\)的右側,就需要新增加圓。其餘的情況只需要調整\(X_A\)的位置,就可以覆蓋到\(B\)點。

參考程式碼

點此展開
#include<iostream>
#include<cmath>
#include<algorithm>

using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const double eps=1e-6;
const int N=1010;

struct node
{
    double x,y;
    bool operator<(const node &a)
    {
        return x<a.x;
    }
}ns[N];

double get_pos(double y,double d)
{
    return sqrt(d*d-y*y);
}

double calc_dis(double cur,double x,double y)
{
    return sqrt(y*y+(x-cur)*(x-cur));
}

int main()
{
    #ifdef LOCAL
    freopen("D:/VSCodeField/C_Practice/a.in", "r", stdin);
    freopen("D:/VSCodeField/C_Practice/a.out", "w", stdout);
    #endif

    int kase=0;
    int n;
    double d;

    while(cin>>n>>d)
    {
        if(n==0&&d<eps)
            break;

        bool has=false;//是否有點不能被覆蓋
        for(int i=0;i<n;i++)
        {
            cin>>ns[i].x>>ns[i].y;
            if(ns[i].y-d>eps)
                has=true;
        }

        cout<<"Case "<<++kase<<": ";
        if(has) cout<<-1<<endl;
        else
        {
            sort(ns,ns+n);

            int res=1;
            double cur=ns[0].x+get_pos(ns[0].y,d);

            for(int i=1;i<n;i++)
            {
                double next_pos=ns[i].x+get_pos(ns[i].y,d);
                if(calc_dis(cur,ns[i].x,ns[i].y)>d)
                {
                    if(next_pos>cur)
                        res++;
                    cur=next_pos;
                }
            }
            cout<<res<<endl;
        }
    }

    return 0;
}