题意:给定两点x1,x2,再给出另外n个点,以x1为圆心r1为半径画圆,以x2为圆心r2为半径画圆,使得另外n个点至少被这两个圆中的一个覆盖到,且r1^2+r2^2最小。
解题思想:计算n个点到x1、x2的距离的平方,将n个点到x1的距离按降序排,最初r1取离x1最远的点到x1的距离的平方,r2为0,显然完全被覆盖了,ans记录此时r1+r2的值。
之后让r1缩小,使得以x1为圆心作的圆刚好覆盖n-1个点,并让以x2为圆心作的圆覆盖第n个点,若此时r1+r2<ans,则更新ans
以后每次这样做,直到r1缩小的0(注意要缩小到0)。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int tw[2][2];
int em[100100][2];
struct Node
{
int id;
int dis;
Node() { dis = 0; }
} d1[100100];
int d2[100100];
inline int calD2(int x1, int y1, int x2, int y2)
{
return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}
bool compare(const Node &a, const Node &b)
{
return a.dis > b.dis;
}
int main()
{
int t, i, n;
scanf ("%d", &t);
while (t--) {
memset(d2, 0, sizeof(d2));
for (i = 0; i < 2; i++)
scanf("%d %d", &tw[i][0], &tw[i][1]);
scanf ("%d", &n);
for (i = 0; i < n; i++)
{
scanf ("%d %d", &em[i][0], &em[i][1]);
d1[i].id = i;
d1[i].dis = calD2(tw[0][0], tw[0][1], em[i][0], em[i][1]);
d2[i] = calD2(tw[1][0], tw[1][1], em[i][0], em[i][1]);
}
sort(d1, d1 + n, compare);
int r2 = 0;
int ans = d1[0].dis;
i = 0;
while (true)
{
if (r2 < d2[d1[i].id]) r2 = d2[d1[i].id];
if (d1[i+1].dis + r2 < ans) ans = d1[i+1].dis + r2;
i++;
if (d1[i].dis == 0) break;
}
printf ("%d\n", ans);
}
return 0;
}