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;
    }
  • 相关阅读:
    day09_request&response学习笔记
    为什么浏览器User-agent(浏览器类型)总是有Mozilla字样?
    无效类字符串:ProgID: Excel.Application
    django2.0升级日记
    Kali Linux信息收集工具
    Kali Linux 工具使用中文说明书
    人手一份核武器
    五大常用算法【转发】
    ACCA AI来袭会议笔记
    2017 Gartner数据科学魔力象限出炉,16位上榜公司花落谁家?
  • 原文地址:https://www.cnblogs.com/ZefengYao/p/7325990.html
Copyright © 2011-2022 走看看