貪心。糾結了好久滴說。剛發現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;}