1. 程式人生 > >Radar Installation POJ - 1328 (區間貪心)

Radar Installation POJ - 1328 (區間貪心)

https://vjudge.net/problem/POJ-1328

一道比較基礎的貪心題目, 比較巧妙的是題中用到了區間貪心的演算法.

起初看題的時候一直有一個誤區, 總想通過分析雷達關於島的位置來確定範圍, 後來發現其實加上一點兒逆向思維, 通過考慮島來確定雷達的範圍其實會更簡單

具體來說, 考慮一下每個小島被覆蓋時雷達的區間, 最後就把各個小島轉化為了一個個區間, 我們的任務就是求最少的點, 使得所有的線段都被覆蓋到, 直接順序列舉+貪心即可

具體的貪心演算法就是對於每個島不斷的和下一個島判斷是否有交集, 有的話再判斷是否改變集合的邊界(也就是真子集與否的判斷)

//建立雷達 貪心
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 1010;
struct Island{
    double left, right;
}isl[maxn];
bool operator < (const Island &a, const Island &b)
{
    return a.left < b.left; //升序
}
int n, d, x, y;
int solve()
{
    sort(isl+1, isl+1+n); //按左端點大小升序排列
    //若當前線段與目前集合中的線段沒有交集, 則加入新的雷達
    double range = isl[1].right; int ans = 1;
    for(int i = 2; i <= n; i++){
        if(isl[i].left <= range) range = min(range, isl[i].right);
        else range = isl[i].right, ans++;
    }
    return ans;
}


int main()
{
    int index = 1;
    while(scanf("%d%d",&n,&d)==2 && (n!=0||d!=0)){
        bool flag = 1;
        memset(isl, 0, sizeof(isl)); //初始化
        for(int i = 1; i <= n; i++){
            scanf("%d%d",&x,&y);
            if(y > d) flag = 0;
            isl[i].left = x - sqrt(d*d-y*y); //計算每個小島決定的雷達範圍
            isl[i].right = x + sqrt(d*d-y*y); //勾股定理
        }
        if(flag) printf("Case %d: %d\n",index++, solve());
        else printf("Case %d: -1\n",index++); //剪枝
    }
    return 0;
}