题目描述
小 w 伤心的走上了 Star way to heaven。
到天堂的道路是一个笛卡尔坐标系上一个 n*m 的长方形通道 顶点在 (0,0) 和 (n,m) 。
小 w 从最左边任意一点进入,从右边任意一点走到天堂,最左最右的距离为 n,上下边界距离为m 。
其中长方形有 k 个Star ,每个 Star 都有一个整点坐标,Star 的大小可以忽略不计。
每个 Star 以及长方形上下两个边缘宇宙的边界都有引力,所以为了成功到达 heaven 小 w 离他们越远越好。
请问小 w 走到终点的路径上,距离所有星星以及边界的最小距离最大值可以为多少?
额,这个题意比较清楚,就是这个小w很想去天堂,但是路上会有讨厌的星星,他想离这些星星越远越好,让我们求距离所有星星以及边界的最小距离最大值。
思路解析
一开始,我想的是把范围会重叠星星们放入一个并查集中,然后再用二分求答案。
然而,做到一半,我突然发现,万一几颗星星在同一个并查集并且它们的总半径恰好等于 m/2m/2m/2 ,那这就意味着,它们直接把路给“堵”着,这道题就用二分做肯定会被卡掉😱。
后来觉得既然它在《最小生成树》里面,后来又想到了用Prim算法。原谅我太蒟蒻(逃
把边界加入集合,再用Prim跑最短路,找距离最小的点然后加入集合,将与之相连的点的距离更新。
直到我们最后添加第二个边界到集合中,这时我们就应该输出了,其实这时的最大值为恰好不能走过去时的最小 did_idi。
又:一定要注意一下 doubledoubledouble。
(实在不了解你可以看看代码嘛)
注释代码
#include <bits/stdc++.h>
#define sf scanf
#define pf printf
#define maxn 6005
#define maxm 1000005
using namespace std;
int n, m, k;
double tmp;
double x[maxn], y[maxn], d[maxn];
bool vis[maxn];
double get (int u, int v) { // 计算两点之间的距离公式
return sqrt ((x[u] - x[v]) * (x[u] - x[v]) + (y[u] - y[v]) * (y[u] - y[v]));
}
int main () {
sf ("%d %d %d", &n, &m, &k);
for (int i = 1; i <= k; i ++)
sf ("%lf %lf", &x[i], &y[i]);
for (int i = 1; i <= k; i ++) {
d[i] = y[i]; // 初始化为纵轴
}
d[k + 1] = m;
for (int i = 1; i <= k + 1; i ++) {
int t = 0;
double now = maxm; // 设置为极大值
for (int j = 1; j <= k + 1; j ++) {
if (! vis[j] && d[j] < now) {
now = d[j];
t = j;
} // 跑最短路,更新d[i]以及其下标
}
tmp = max (d[t], tmp); // 更新tmp
if (t == k + 1) { // 添加到最后一个边界,可以输出了
pf ("%.9f", tmp / 2);
return 0;
}
vis[t] = 1; // 标记ta
for (int j = 1; j <= k; j ++) {
double tmp = get (j, t); // 计算距离(tmp再利用)
if (! vis[j]) {
d[j] = min (d[j], max (d[t], tmp)); // 更新
}
}
d[k + 1] = min (d[k + 1], m - y[t]); // 继续按题意更新
}
}
感谢阅读