题目链接
分析
此题可以暴力二分,但是只有80pts,所以不采纳这个思想。
考虑与最小生成树的关系,当所有的引力把能走的路全部封死之后,此时的(ans)便是最大的引力圈的半径。
step1
首先初始化(dis[i] = m - y[i]),把dis[k+1]设为m。
step2
然后用(Prim)不停遍历,如果此时找的最近节点为(k+1)说明已经遍历完毕,直接退出,
ans更新成ans与dis[falg]之间的大者。
然后更xin(dis[i](i∈k)), 更新(dis[k+1]=min(dis[k+1], y[falg]))
最后输出(ans/2)。
代码
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 6005;
const int MAXM = 1e6 + 5;
int n, m, k;
double x[MAXN], y[MAXN], dis[MAXN], ans;
bool vis[MAXN];
double Dist(int u, int v) {
return sqrt((x[u] - x[v]) * (x[u] - x[v]) + (y[u] - y[v]) * (y[u] - y[v]));
}
int main() {
scanf ("%d %d %d", &n, &m, &k);
for (int i = 1; i <= k; i++) {
scanf ("%lf %lf", &x[i], &y[i]);
dis[i] = (m * 1.0) - y[i];
}
dis[k + 1] = m;
dis[0] = INF;
ans = -1;
while (1) {
int flag = 0;
for (int i = 1; i <= k + 1; i++) {
if (vis[i] == 0 && dis[i] < dis[flag]) flag = i;
}
vis[flag] = 1;
ans = max(ans, dis[flag]);
if (flag == k + 1) break;
for (int i = 1; i <= k; i++) {
dis[i] = min(dis[i], Dist(i, flag));
}
dis[k + 1] = min(dis[k + 1], y[flag]);
}
printf ("%.9lf", ans / 2);
return 0;
}