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;
}

 

转载于:https://www.cnblogs.com/ZefengYao/p/7325990.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牙科就诊管理系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线查看数据。管理员管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等功能。牙科就诊管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 管理员在后台主要管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等。 牙医列表页面,此页面提供给管理员的功能有:查看牙医、新增牙医、修改牙医、删除牙医等。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。药品管理页面,此页面提供给管理员的功能有:新增药品,修改药品,删除药品。药品类型管理页面,此页面提供给管理员的功能有:新增药品类型,修改药品类型,删除药品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值