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