题意:
给你n个点和点的位置,问单位圆最多能覆盖多少个点。
题目:
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.
Fig 1. Circle and Points
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
分析:
(1).极限思维,我们可以思考,若有这样的一个覆盖最多的点,我们可以使至少某一点在这个圆的圆弧上。
(2).先只固定一个点i,该点的单位圆与其他点j的单位圆相交,形成i圆上的一段弧,该弧被j圆覆盖。最终圆如果在该弧上,则一定能覆盖j点。那么问题归结于找出i圆上被覆盖次数最多的一段弧。
(3).至于弧的表示,可以用相交的两个点表示,由于所有在弧上的点都可以用角度表示(对于固定一个点,且确定圆为单位圆,半径为一)类似于一个区间。
(4)问题就转化成怎么求覆盖的区域,我们用扫描线的思想,B圆与A圆交于点a,a1与C交于点b,b1,sort排序后,我们令方向为逆时针(两点我们用极角表示,所以入点一定小于出点),这个时候每两个交点都有一个入点一个出点,遇到一个入点我们就+1,遇到出点我们就-1,这样就能表示出被覆盖的次数。
AC模板:
#include<cmath>
#include<cstdio>>
#include<iostream>
#include<algorithm>
using namespace std;
const int mm=333;
typedef double diy;
struct point
{diy x,y;//point(){}//point(diy _x,diy _y):x(_x),y(_y){}
}g[mm];
struct alpha
{diy angle;bool flag;
}s[mm];
bool cmp(alpha P,alpha Q)
{return P.angle<Q.angle;
}
diy SqrDis(point P,point Q)
{return (P.x-Q.x)*(P.x-Q.x)+(P.y-Q.y)*(P.y-Q.y);
}
int CircleMaxPoint(int n,diy r)
{int i,j,m,sum,ret=n>0;double tmp,rad;for(i=0;i<n;++i){m=0;for(j=0;j<n;++j)if(i!=j&&(tmp=SqrDis(g[i],g[j]))<=4){rad=acos(sqrt(tmp)/2);tmp=atan2(g[j].y-g[i].y,g[j].x-g[i].x);s[m].angle=tmp-rad,s[m++].flag=1;s[m].angle=tmp+rad,s[m++].flag=0;}sort(s,s+m,cmp);for(sum=j=0;j<m;++j){if(s[j].flag)++sum;else --sum;ret=max(ret,sum+1);}}return ret;
}
int main()
{int i,n;while(scanf("%d",&n),n){for(i=0;i<n;++i)scanf("%lf%lf",&g[i].x,&g[i].y);printf("%d\n",CircleMaxPoint(n,1.0));}return 0;
}