poj 1981 Circle and Points (模板)

套圈:平面上有N个点,用单位圆去套,最多能套几个?


极限情况 

所谓极限情况就是单位圆上有两个点,稍微动一下就会损失一个点,覆盖点最多的圆一定有一个是这种圆(当然当N=1的时候是个例外)。朴素想法是先固定两个点,然后枚举其他的点是否在这两个点决定的两个圆内,朴素得掉渣我就不写了。

更快的算法是,先只固定一个点i,该点的单位圆与其他点j的单位圆相交,形成i圆上的一段弧,该弧被j圆覆盖。最终圆如果在该弧上,则一定能覆盖j点。那么问题归结于找出i圆上被覆盖次数最多的一段弧。

至于弧的表示,用两个极角表示,分别为起始和终止,类似于一个区间。枚举完其他点之后,得到N-1个区间。将其排序后,从前往后扫描,碰到起始计数+1,碰到终止计数-1,同时更新答案。

至于极角的求解,三角函数我全忘光了……查了查维基才记起来,如图:

其中,acos的定义如下:

atan2的定义如下:

那么就可以愉快地写代码了:

  1. #include<cstdio>
  2. #include<cmath>
  3. #include<algorithm>
  4.  
  5. using namespace std;
  6.  
  7. #define MAX_N 300 + 16
  8.  
  9. typedef double p_type;
  10.  
  11. struct Point
  12. {
  13. p_type x, y;
  14.  
  15. Point(){}
  16.  
  17. Point(p_type x, p_type y) : x(x), y(y){}
  18. } ps[MAX_N];
  19.  
  20. struct PolarAngle
  21. {
  22. p_type angle;
  23. bool flag; // 起点或终点
  24.  
  25. const bool operator<(const PolarAngle &other)
  26. {
  27. return angle < other.angle;
  28. }
  29. } as[MAX_N];
  30.  
  31. inline p_type distance_of(const Point &P, const Point &Q)
  32. {
  33. return sqrt((P.- Q.x) * (P.- Q.x) + (P.- Q.y) * (P.- Q.y));
  34. }
  35.  
  36. inline int solve(const int& n, const p_type& r)
  37. {
  38. int result = 1;
  39. for (int i = 0; i < n; ++i)
  40. {
  41. int m = 0;
  42. double d;
  43. for (int j = 0; j < n; ++j)
  44. {
  45. if (!= j && (= distance_of(ps[i], ps[j])) <= 2)
  46. {
  47. double phi = acos(/ 2);
  48. double theta = atan2(ps[j].- ps[i].y, ps[j].- ps[i].x);
  49. as[m].angle = theta - phi, as[m++].flag = 1;
  50. as[m].angle = theta + phi, as[m++].flag = 0;
  51. }
  52. }
  53. sort(as, as + m);
  54. for (int sum = 1, j = 0; j < m; ++j)
  55. {
  56. if (as[j].flag)
  57. ++sum;
  58. else
  59. --sum;
  60. result = max(result, sum);
  61. }
  62. }
  63. return result;
  64. }
  65.  
  66. ///SubMain//
  67. int main(int argc, char *argv[])
  68. {
  69. #ifndef ONLINE_JUDGE
  70. freopen("in.txt", "r", stdin);
  71. freopen("out.txt", "w", stdout);
  72. #endif
  73. int N;
  74. while (scanf("%d", &N), N)
  75. {
  76. for (int i = 0; i < N; ++i)
  77. {
  78. scanf("%lf%lf", &ps[i].x, &ps[i].y);
  79. }
  80. printf("%d\n", solve(N, 1.0));
  81. }
  82. #ifndef ONLINE_JUDGE
  83. fclose(stdin);
  84. fclose(stdout);
  85. system("out.txt");
  86. #endif
  87. return 0;
  88. }

上面的解法并不能看懂,先放这里!
所以就用下面的模板吧

#include <iostream>

#include <cstdio>

#include <cmath>

#include <algorithm>

using namespace std;

 

double eps=1e-8;

double r = 2.5;

 

struct Point

{

    double x,y;

    Point() {}

    Point(double tx,double ty)

    {

        x=tx;

        y=ty;

    }

}p[300];

double dist(Point p1,Point p2)

{

    return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));

}

 

Point get_circle(Point p1,Point p2)

{

         Point mid = Point((p1.x+p2.x)/2,(p1.y+p2.y)/2);

         double angle = atan2(p1.x-p2.x,p2.y-p1.y);

         double d = sqrt(r*r-pow(dist(p1,mid),2));

         return Point(mid.x+d*cos(angle),mid.y+d*sin(angle));

}

 

int main()

{

    //freopen("in.txt","r",stdin);

    int num = 0;

    double a,b;

    while(scanf("%lf%lf",&a,&b) != EOF)

    {

        p[num].x = a;

        p[num].y = b;

        num++;

    }

    int i,j;

    int ans = 1;

    for(i=0; i<num; i++)

    {

        for(j=i+1; j<num; j++)

        {

            if(dist(p[i],p[j]) > 2.0*r) continue;

            Point center = get_circle(p[i],p[j]);

            int cnt = 0;

            for(int k=0; k<num; k++)

                if(dist(center,p[k]) < 1.0*r+eps) cnt++;

            ans = max(ans,cnt);

        }

    }

    cout<<ans<<endl;

    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值