题目:
http://poj.org/problem?id=1328
题意:
给定若干点,以及半径长度d,问至少需要多少个这样的半圆才能把所有点覆盖掉
思路:
一开始的贪心策略是把点按照x坐标升序排序,每次把圆心定在尽可能右边的位置,然后一直wa >_<
这种策略会在
2 3
0 2
0 3
这种数据上被坑
同理对排序加上x相同时,y降序排序的优化后,会死在这种数据上
2 3
0 1
1 3
正确的贪心方法应该是把每个点允许的圆心范围算出来,对每个圆心区间进行排序贪心
代码:
#include <stdio.h>
#include <math.h>
struct pos{
double beg, end;
};
void sort(pos arr[],int l, int r){
int i = l, j = r;
pos mid = arr[(l + r) >> 1];
while (i <= j){
while ((arr[i].beg < mid.beg) || (arr[i].beg == mid.beg && arr[i].end<mid.end)) ++i;
while ((arr[j].beg > mid.beg) || (arr[j].end == mid.end && arr[j].end<mid.end)) --j;
if (i <= j){
pos t = arr[i];
arr[i] = arr[j];
arr[j] = t;
++i;
--j;
}
}
if (i < r) sort(arr, i, r);
if (j > l) sort(arr, l, j);
return;
}
int main(){
int n, d, total = 0;
pos arr[1005];
while (scanf("%d %d", &n, &d), ++total, !(n == 0 && d == 0)){
int ans = 1;
for (int i = 0; i < n; ++i){
int x, y;
scanf("%d %d", &x, &y);
if (y <= d){
double t = sqrt(d*d - y*y*1.0);
arr[i].beg = x - t;
arr[i].end = x + t;
}
else ans = -1;
}
getchar();
//in
if (ans != -1){
sort(arr, 0, n - 1);
double radBeg = arr[0].beg, radEnd = arr[0].end;
for (int i = 1; i < n; ++i){
if (radEnd>=arr[i].beg){
radBeg = arr[i].beg;
radEnd = radEnd>arr[i].end ? arr[i].end : radEnd;
}
else{
++ans;
radBeg = arr[i].beg;
radEnd = arr[i].end;
}
}
}
printf("Case %d: %d\n", total, ans);
}
return 0;
}