此题可以暴力二分,但是只有80pts,所以不采纳这个思想。
考虑与最小生成树的关系,当所有的引力把能走的路全部封死之后,此时的\(ans\)便是最大的引力圈的半径。
首先初始化\(dis[i] = m - y[i]\),把dis[k+1]设为m。
然后用\(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;
}
原文:https://www.cnblogs.com/cqbz-ChenJiage/p/13514456.html