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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM