套圈:平面上有N个点,用单位圆去套,最多能套几个?
极限情况
所谓极限情况就是单位圆上有两个点,稍微动一下就会损失一个点,覆盖点最多的圆一定有一个是这种圆(当然当N=1的时候是个例外)。朴素想法是先固定两个点,然后枚举其他的点是否在这两个点决定的两个圆内,朴素得掉渣我就不写了。
更快的算法是,先只固定一个点i,该点的单位圆与其他点j的单位圆相交,形成i圆上的一段弧,该弧被j圆覆盖。最终圆如果在该弧上,则一定能覆盖j点。那么问题归结于找出i圆上被覆盖次数最多的一段弧。
至于弧的表示,用两个极角表示,分别为起始和终止,类似于一个区间。枚举完其他点之后,得到N-1个区间。将其排序后,从前往后扫描,碰到起始计数+1,碰到终止计数-1,同时更新答案。
至于极角的求解,三角函数我全忘光了……查了查维基才记起来,如图:
其中,acos的定义如下:
atan2的定义如下:
那么就可以愉快地写代码了:
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- using namespace std;
- #define MAX_N 300 + 16
- typedef double p_type;
- struct Point
- {
- p_type x, y;
- Point(){}
- Point(p_type x, p_type y) : x(x), y(y){}
- } ps[MAX_N];
- struct PolarAngle
- {
- p_type angle;
- bool flag; // 起点或终点
- const bool operator<(const PolarAngle &other)
- {
- return angle < other.angle;
- }
- } as[MAX_N];
- inline p_type distance_of(const Point &P, const Point &Q)
- {
- return sqrt((P.x - Q.x) * (P.x - Q.x) + (P.y - Q.y) * (P.y - Q.y));
- }
- inline int solve(const int& n, const p_type& r)
- {
- int result = 1;
- for (int i = 0; i < n; ++i)
- {
- int m = 0;
- double d;
- for (int j = 0; j < n; ++j)
- {
- if (i != j && (d = distance_of(ps[i], ps[j])) <= 2)
- {
- double phi = acos(d / 2);
- double theta = atan2(ps[j].y - ps[i].y, ps[j].x - ps[i].x);
- as[m].angle = theta - phi, as[m++].flag = 1;
- as[m].angle = theta + phi, as[m++].flag = 0;
- }
- }
- sort(as, as + m);
- for (int sum = 1, j = 0; j < m; ++j)
- {
- if (as[j].flag)
- ++sum;
- else
- --sum;
- result = max(result, sum);
- }
- }
- return result;
- }
- ///SubMain//
- int main(int argc, char *argv[])
- {
- #ifndef ONLINE_JUDGE
- freopen("in.txt", "r", stdin);
- freopen("out.txt", "w", stdout);
- #endif
- int N;
- while (scanf("%d", &N), N)
- {
- for (int i = 0; i < N; ++i)
- {
- scanf("%lf%lf", &ps[i].x, &ps[i].y);
- }
- printf("%d\n", solve(N, 1.0));
- }
- #ifndef ONLINE_JUDGE
- fclose(stdin);
- fclose(stdout);
- system("out.txt");
- #endif
- return 0;
- }
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
double eps=1e-8;
double r = 2.5;
struct Point
{
double x,y;
Point() {}
Point(double tx,double ty)
{
x=tx;
y=ty;
}
}p[300];
double dist(Point p1,Point p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
Point get_circle(Point p1,Point p2)
{
Point mid = Point((p1.x+p2.x)/2,(p1.y+p2.y)/2);
double angle = atan2(p1.x-p2.x,p2.y-p1.y);
double d = sqrt(r*r-pow(dist(p1,mid),2));
return Point(mid.x+d*cos(angle),mid.y+d*sin(angle));
}
int main()
{
//freopen("in.txt","r",stdin);
int num = 0;
double a,b;
while(scanf("%lf%lf",&a,&b) != EOF)
{
p[num].x = a;
p[num].y = b;
num++;
}
int i,j;
int ans = 1;
for(i=0; i<num; i++)
{
for(j=i+1; j<num; j++)
{
if(dist(p[i],p[j]) > 2.0*r) continue;
Point center = get_circle(p[i],p[j]);
int cnt = 0;
for(int k=0; k<num; k++)
if(dist(center,p[k]) < 1.0*r+eps) cnt++;
ans = max(ans,cnt);
}
}
cout<<ans<<endl;
return 0;
}