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\n",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\n"); 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\n",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;
}

 

posted on 2017-08-09 16:20  ZefengYao  阅读(274)  评论(0编辑  收藏  举报

导航