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 }