zoukankan      html  css  js  c++  java
  • poj 1981 Circle and Points

    Circle and Points
    Time Limit: 5000MS   Memory Limit: 30000K
    Total Submissions: 8131   Accepted: 2899
    Case Time Limit: 2000MS

    Description

    You are given N points in the xy-plane. You have a circle of radius one and move it on the xy-plane, so as to enclose as many of the points as possible. Find how many points can be simultaneously enclosed at the maximum. A point is considered enclosed by a circle when it is inside or on the circle. 

    Input

    The input consists of a series of data sets, followed by a single line only containing a single character '0', which indicates the end of the input. Each data set begins with a line containing an integer N, which indicates the number of points in the data set. It is followed by N lines describing the coordinates of the points. Each of the N lines has two decimal fractions X and Y, describing the x- and y-coordinates of a point, respectively. They are given with five digits after the decimal point. 

    You may assume 1 <= N <= 300, 0.0 <= X <= 10.0, and 0.0 <= Y <= 10.0. No two points are closer than 0.0001. No two points in a data set are approximately at a distance of 2.0. More precisely, for any two points in a data set, the distance d between the two never satisfies 1.9999 <= d <= 2.0001. Finally, no three points in a data set are simultaneously very close to a single circle of radius one. More precisely, let P1, P2, and P3 be any three points in a data set, and d1, d2, and d3 the distances from an arbitrarily selected point in the xy-plane to each of them respectively. Then it never simultaneously holds that 0.9999 <= di <= 1.0001 (i = 1, 2, 3). 

    Output

    For each data set, print a single line containing the maximum number of points in the data set that can be simultaneously enclosed by a circle of radius one. No other characters including leading and trailing spaces should be printed.

    Sample Input

    3
    6.47634 7.69628
    5.16828 4.79915
    6.69533 6.20378
    6
    7.15296 4.08328
    6.50827 2.69466
    5.91219 3.86661
    5.29853 4.16097
    6.10838 3.46039
    6.34060 2.41599
    8
    7.90650 4.01746
    4.10998 4.18354
    4.67289 4.01887
    6.33885 4.28388
    4.98106 3.82728
    5.12379 5.16473
    7.84664 4.67693
    4.02776 3.87990
    20
    6.65128 5.47490
    6.42743 6.26189
    6.35864 4.61611
    6.59020 4.54228
    4.43967 5.70059
    4.38226 5.70536
    5.50755 6.18163
    7.41971 6.13668
    6.71936 3.04496
    5.61832 4.23857
    5.99424 4.29328
    5.60961 4.32998
    6.82242 5.79683
    5.44693 3.82724
    6.70906 3.65736
    7.89087 5.68000
    6.23300 4.59530
    5.92401 4.92329
    6.24168 3.81389
    6.22671 3.62210
    0
    

    Sample Output

    2
    5
    5
    11

    翻译:给定平面坐标N个点,现在想用一个单位圆覆盖尽可能多的点,问最多能覆盖多少点。
    思路:朴素做法:枚举任意两个点,求出过这两个点的单位圆的圆心,在看看这个这个单位圆能覆盖多少点,取最大即可。
    AC代码:
    #define _CRT_SECURE_NO_DEPRECATE
    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<vector>
    #include<cstring>
    #include<string>
    #include<functional>
    #include<cmath>
    #include<stack>
    using namespace std;
    #define INF 0x3f3f3f3f
    const int N_MAX=300+15;
    double EPS = 1e-10;
    struct P {
        double x, y;
        P(double x=0,double y=0):x(x),y(y){}
    }ps[N_MAX];
    int N;
    
    //距离平方
    double dist(const P&a,const P&b) {
        return (a.x - b.x)*(a.x - b.x)+(a.y - b.y)*(a.y - b.y);//!!!!
    }
    //找圆心
    P find_circle(const P& p1,const P& p2,int flag) {
        double phi = atan2(p2.y-p1.y,p2.x-p1.x);
        double d = sqrt(dist(p1, p2));
        double theta = flag*acos(d/2)+phi;
        P c;
        c.x = p1.x + cos(theta);
        c.y = p1.y + sin(theta);
        return c;
    }
    
    void solve() {
        int res = 1;
        for (int i = 0; i < N;i++) {
            for (int j = i+1; j < N;j++) {
                if (dist(ps[i], ps[j])<=4) {//两点距离小于2,可在一个圆上
                    P c1 = find_circle(ps[i], ps[j], 1);
                    P c2 = find_circle(ps[i], ps[j], -1);
                    int num1=2, num2=2;
                    for (int k = 0; k < N;k++) {
                        if (k != i&&k != j) {
                            if (dist(c1, ps[k]) <= 1)num1++;
                            if (dist(c2, ps[k]) <= 1)num2++;
                        }
                    }
                    res = max(res, num1);
                    res = max(res, num2);
                }
            }
        }
        printf("%d
    ",res);
    }
    
    int main() {
        while (scanf("%d",&N)&&N) {
            for (int i = 0; i < N;i++) {
                scanf("%lf%lf",&ps[i].x,&ps[i].y);
            }
            if (N == 1) { printf("1
    "); continue; }
            solve();
        }
        return 0;
    }

    思路2:我们先考虑其中的两个点,分别以这两个点为圆心画单位圆,如果两点距离足够近,则两圆一定会相交并且分别有一段相交的弧,不妨考虑其中的一段弧,如果我们最终需要找的那个圆的圆心就在这段弧上,那么这个圆一定会经过刚才所考虑的那两个点。那么我们每次固定一个点,以这个点为圆心画单位圆与其他的N-1个点为圆心的单位圆分别相交,会在这个点为圆心的圆上产生很多的相交弧,则最终那个圆的圆心若在相交弧重叠部分越多的地方,则可以包含更多的点。

    AC代码:

    #define _CRT_SECURE_NO_DEPRECATE
    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<vector>
    #include<cstring>
    #include<string>
    #include<functional>
    #include<cmath>
    #include<stack>
    using namespace std;
    #define INF 0x3f3f3f3f
    const int N_MAX=300+15;
    double EPS = 1e-10;
    struct P {
        double x, y;
        P(double x=0,double y=0):x(x),y(y){}
    }ps[N_MAX];
    int N;
    struct Bow {
        double angle;
        bool flag;//0代表初始,1代表终止
        bool operator <(const Bow&b)const {
            return this->angle < b.angle;
        }
    }bow[N_MAX];
    //距离的平方
    double dist(const P&a,const P&b) {
        return (a.x - b.x)*(a.x - b.x)+(a.y - b.y)*(a.y - b.y);//!!!!
    }
    
    void solve() {
        int res_max = 1;//res_max记录单位圆能包含的最多的顶点数
        for (int i = 0; i < N;i++) {//对于每一个点
            int  k = 0;//记录交弧的个数    
            for (int j = 0; j < N; j++) {
                double d = sqrt(dist(ps[i], ps[j]));
                if (j != i&&d <= 2) {//i,j为圆心的圆相交
                    double phi = acos(d / 2);
                    double theta = atan2(ps[j].y - ps[i].y, ps[j].x - ps[i].x);
                    bow[k].angle = theta - phi; bow[k++].flag = 0;
                    bow[k].angle = theta + phi; bow[k++].flag = 1;
                }
            }
                int res = 1;//当前单位圆能包含的顶点数
                sort(bow, bow + k);
                for (int l = 0; l < k;l++) {
                    if (!(bow[l].flag))res++;
                    else res--;
                    res_max = max(res_max, res);
                }
        }
        printf("%d
    ",res_max);
    }
    
    int main() {
        while (scanf("%d",&N)&&N) {
            for (int i = 0; i < N;i++) {
                scanf("%lf%lf",&ps[i].x,&ps[i].y);
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    Linux常用命令学习
    LA 6437 Power Plant (prim最小生成树)
    Atitit.提升稳定性-----分析内存泄漏PermGen OOM跟解决之道...java
    hdu 1248 寒冰王座
    数据结构——算法之(031)(将字符串中全部小写字母排在大写字母的前面)
    X-射线:探索原子世界的利器
    关于sql中的with(nolock)
    Netty In Action中文版
    抓包报文分析
    POJ 1562 Oil Deposits
  • 原文地址:https://www.cnblogs.com/ZefengYao/p/7325990.html
Copyright © 2011-2022 走看看