已知在平面上有若干个点,求一个已知半径的圆最多更覆盖多少个点。
一个比较经典的问题。(另一个为已知若干个点,求能覆盖住所有点的圆的最小半径。)
两两点枚举,分别以两点为圆心,已知半径画圆,若相交,则求出两圆的一个交点(两边可任意,但是每两个圆的交点都要取同一边的),然后判断以交点为圆心已知半径为半径的圆能覆盖多少个点(在圆上也算)。逐个更新ans,直到枚举完全,最后ans的值即为能覆盖住的点的最大个数。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
struct point
{
double x, y;
};
double dis(point p1, point p2) //两点间距离平方
{
point p3;
p3.x = p2.x - p1.x;
p3.y = p2.y - p1.y;
return p3.x * p3.x + p3.y * p3.y;
}
point find_centre(point p1, point p2) //找到固定半径圆的圆心位置,圆心均应找在连线的同一边
{
point p3, mid, centre;
double b, c, ang;
p3.x = p2.x - p1.x;
p3.y = p2.y - p1.y;
mid.x = (p1.x + p2.x) / 2;
mid.y = (p1.y + p2.y) / 2;
b = dis(p1, mid);
c = sqrt(6.25 - b);
if(fabs(p3.y) < 0.000001) //两圆心连线的垂线的斜角90度
{
centre.x = mid.x;
centre.y = mid.y + c;
}
else
{
ang = atan(-p3.x / p3.y);
centre.x = mid.x + c * cos(ang);
centre.y = mid.y + c * sin(ang);
}
return centre;
}
int main()
{
int n, ans, tmpans, i, j, k;
point p[205], centre;
double tmp;
n=0;
while(scanf("%lf%lf", &p[n].x, &p[n].y)!=EOF )
{
n++;
}
ans = 1;
for(i = 0;i < n;i++) //两两圆枚举所有情况
for(j = i + 1;j < n;j++)
{
if(dis(p[i], p[j]) >25) continue; //当以这两个点为圆心画的圆不相交时直接跳过
tmpans = 0;
centre = find_centre(p[i], p[j]);
for(k = 0;k < n;k++) //判断以新圆心为圆心时的圆覆盖住的点的个数
{
tmp = dis(centre, p[k]);
if(tmp <= 6.25) tmpans++;
}
if(ans < tmpans) ans = tmpans;
}
printf("%d\n", ans);
return 0;
}