贪心。纠结了好久滴说。刚发现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; }