http://poj.org/problem?id=1981
题意:给定N个点,用一个半径1的圆去覆盖,最多能覆盖多少个点?
思路:如果只有一个点,那么输出1
O(N^3)暴力!!4700+
一个覆盖最多点的圆,必然至少有两个点在圆上。
枚举两个点,求过这两个点的单位圆,判断有多少个点在圆中,枚举N^2,判断N

1 #include <stdio.h> 2 #include <string.h> 3 #include <math.h> 4 #include <iostream> 5 using namespace std; 6 #define eps 1e-8 7 struct Point{ 8 double x,y; 9 Point(){} 10 Point(double tx,double ty){x=tx;y=ty;} 11 }p[300]; 12 int n; 13 double dist(Point p1,Point p2){ 14 return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); 15 } 16 Point get_circle(Point p1,Point p2){ 17 Point mid=Point((p1.x+p2.x)/2,(p1.y+p2.y)/2); 18 double angle=atan2(p1.x-p2.x,p2.y-p1.y); 19 double d=sqrt(1-dist(p1,mid)*dist(p1,mid)); 20 return Point(mid.x+d*cos(angle),mid.y+d*sin(angle)); 21 } 22 int main(){ 23 while(scanf("%d",&n)!=EOF&&n){ 24 for(int i=0;i<n;i++) 25 scanf("%lf%lf",&p[i].x,&p[i].y); 26 int ans=1; 27 for(int i=0;i<n;i++){ 28 for(int j=i+1;j<n;j++){ 29 if(dist(p[i],p[j])>2.0) continue; 30 Point central=get_circle(p[i],p[j]); 31 int cnt=0; 32 for(int k=0;k<n;k++) 33 if(dist(central,p[k])<1.0+eps) 34 cnt++; 35 ans=max(ans,cnt); 36 } 37 } 38 printf("%d\n",ans); 39 } 40 return 0; 41 }
O(N^2logN) 1100+
枚举每个点,以该点为圆心画单位圆,用“圆O”表示,内层的枚举以剩下的点画单位圆,看看这些圆和圆O的交(就是相交弧),如果有交点,每个圆产生两个交点,
然后对产生的2n个交点极角排序,判断被覆盖最多的弧,被覆盖相当于这个弧上的点为圆心的圆可以覆盖到覆盖它的那些点,所以被覆盖最多的弧就是答案了。
Ps:求交点时可以用一种巧妙的方法,那就是求出2个圆心的斜率并用arctan求出相差的角度(邻边是圆心距/2,斜边是R)。

1 #include <stdio.h> 2 #include <iostream> 3 #include <cmath> 4 #include <algorithm> 5 #define PI acos(-1.0) 6 using namespace std; 7 const int N=305; 8 int n; 9 struct Point{double x,y;}p[N]; 10 struct Angle{double ang;bool is;}angle[N*2]; 11 int cmp(Angle M,Angle N){ 12 return M.ang<N.ang; 13 } 14 double dist(Point a,Point b){ 15 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); 16 } 17 double k(Point a,Point b){ 18 double ki=atan(fabs((b.y-a.y)/(b.x-a.x))); 19 if(b.y-a.y>0){ 20 if(b.x-a.x<0) 21 ki=PI-ki; 22 } 23 else{ 24 if(b.x<a.x) ki+=PI; 25 else ki=2*PI-ki; 26 } 27 return ki; 28 } 29 void solve(){ 30 int res=1,top; 31 double dis,now,tmp; 32 for(int i=0;i<n;i++){ 33 top=0; 34 for(int j=0;j<n;j++){ 35 if(i==j) continue; 36 dis=dist(p[i],p[j]); 37 if(dis>2.0) continue; 38 now=k(p[i],p[j]); 39 tmp=acos(dis/2.0); 40 angle[top].ang=now-tmp; 41 angle[top++].is=1; 42 angle[top].ang=now+tmp; 43 angle[top++].is=0; 44 } 45 if(top<res) continue; 46 sort(angle,angle+top,cmp); 47 int count=1; 48 for(int j=0;j<top;j++){ 49 if(angle[j].is) count++; 50 else count--; 51 res=max(res,count); 52 } 53 } 54 printf("%d\n",res); 55 } 56 int main(){ 57 while(scanf("%d",&n)!=EOF&&n){ 58 for(int i=0;i<n;i++){ 59 scanf("%lf%lf",&p[i].x,&p[i].y); 60 } 61 solve(); 62 } 63 }