poj1981 单位圆覆盖

http://poj.org/problem?id=1981

题意:给定N个点,用一个半径1的圆去覆盖,最多能覆盖多少个点?

思路:如果只有一个点,那么输出1

         O(N^3)暴力!!4700+

         一个覆盖最多点的圆,必然至少有两个点在圆上。

         枚举两个点,求过这两个点的单位圆,判断有多少个点在圆中,枚举N^2,判断N

View Code
 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)。  

View Code
 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 }

 

posted @ 2012-10-11 14:07  _sunshine  阅读(2732)  评论(4编辑  收藏  举报