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;
}

猜你喜欢

转载自blog.csdn.net/a1097304791/article/details/83018053