贪心。纠结了好久滴说。刚发现ZOJ也有这个题,顺便A了。
开始我想的贪心算法是错的,就是如果遇到新点,就把新点作为圆上最左边的一点。。其实是不对的,因为有些情况完全可以上个圆经过右移然后覆盖掉。
所以我的算法是:以第一个点为圆的左端端点,求圆心,然后看下一个点,如果这个点没在前面那个圆内,就以当前点作为左端点做一个圆心,如果这个圆心可以覆盖之前那个圆覆盖的所有点,就相当于把这个圆向右移。
如果覆盖不完全,就以这个点位左端点重新做一个圆。
复杂度不太好计算,目测最坏是N^2。。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <climits>
#include <cstring>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)
using namespace std;
const int MAX = 1010;
struct point{
int x, y;
bool operator<(const point &a) const {
if( a.x == x )
return y < a.y;
return x < a.x;
}
};
point p[MAX];
int ind[MAX];
int f[MAX];
void Rcenter(point p, double& cx, int d) {
cx = p.x + sqrt(d*d - p.y*p.y*1.0);
}
bool notIn(point p, double cx, int d) {
return (p.x - cx) * (p.x - cx) + p.y * p.y > d * d;
}
bool canCover(int ans, double cx, int d) {
int i = f[ans];
while( ind[i] == ans ) {
if( notIn(p[i++], cx, d) )
return false;
}
return true;
}
int solve(int n, int d) {
memset(ind, 0, sizeof(ind));
int ans = 1;
sort(p, p+n);
if( p[0].y > d )
return -1;
ind[0] = 1;
f[1] = 0;
double cx;
Rcenter(p[0], cx, d);
FOR(i, 1, n) {
if( abs(p[i].y) > d )
return -1;
if( notIn(p[i], cx, d) ) {
double t = cx;
Rcenter(p[i], t, d);
if( canCover(ans, t, d) ) {
cx = t;
ind[i] = ans;
} else {
ans++;
Rcenter(p[i], cx, d);
ind[i] = ans;
f[ans] = i;
}
} else {
ind[i] = ans;
}
}
return ans;
}
int main()
{
int n, d;
int ncases = 1;
while( cin >> n >> d ) {
if( n == 0 && d == 0 )
break;
FOR(i, 0, n)
cin >> p[i].x >> p[i].y;
cout << "Case " << ncases++ << ": " ;
if( d <= 0 ) {
cout << -1 << endl;
continue;
}
int ans = solve(n, d);
cout << ans << endl;
}
return 0;
}