http://poj.org/problem?id=1328

题意:在x轴上画最少的同半径圆,覆盖x轴上方的若干个点。

非常经典的贪心,每个点有个对应的管辖区间,按右边界点排序之后,从左向右枚举。每一个点假如没被覆盖,则选择它对应的右边界点,这样有机会包含更多的点。

可以说,按右边界排序、从左向右扫描,每次取最右边界已经成为贪心的套路了。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;

bool vis[1005];
pair<double, int> pl[1005], pr[1005];

int ptop;

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n, d, ca = 0;
    while(~scanf("%d%d", &n, &d)) {
        if(n == 0)
            break;
        int x, y;
        int suc = 1;
        ptop = 0;
        memset(vis, 0, sizeof(vis));

        for(int i = 1; i <= n; ++i) {
            scanf("%d%d", &x, &y);
            if(y > d) {
                suc = 0;
                continue;
            }
            double dx = sqrt(1.0 * d * d - 1.0 * y * y);
            pl[++ptop] = {1.0 * x - dx, i};
            pr[ptop] = {1.0 * x + dx, i};
        }
        if(suc == 0) {
            printf("Case %d: -1\n", ++ca);
            continue;
        }
        sort(pl + 1, pl + 1 + ptop);
        sort(pr + 1, pr + 1 + ptop);
        int cnt = 0;
        int j = 1;
        double curl = -1e9;
        for(int i = 1; i <= ptop; ++i) {
            if(vis[pr[i].second] == 0) {
                cnt++;
                curl = pr[i].first + 1e-10;
                while(j <= ptop && pl[j].first <= curl) {
                    vis[pl[j].second] = 1;
                    ++j;
                }
            }
        }
        printf("Case %d: %d\n", ++ca, cnt);
    }
}
02-11 04:30