题目大意
给定起始点和终点的坐标,然后再给几个中间点的坐标,问怎么走可以使得从起点到终点最长的跳跃路径最短。
思路
刚刚学会这个最短路算法还不是很熟练,但我拿到题很快就wa了,因为我想当然的套了个dj算法模版,并没有思考题意,当我重新读题,发现这并不是一道简单的从起点到终点最短路问题,而是最长跨越距离最短的问题。
这样d[i]就不在表示从起点到i点最短路径了,而是表示从起点到i点的最大跳跃距离。
然后就是dj算法那个思路,写着写着发现这个算法和之前接触的prim算法有点像诶~
这道题与普通最短路的区别和联系
1.区别:普通最短路问题是两个点通过加入其他点更新这两个的最短距离,而这里不一样之处在于更新的不是最短距离而是最长跳跃的最短距离,所以d[i]的含义有所不同。
2.联系:dj的基本思路是完全一样的,都是贪心的思想找到最合题的点,用这个点更新其他点。
代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int maxn = 200 + 10;
const int inf = 0x3f3f3f3f;
double d[maxn]; // d[i] 表示从 1 出发 到 i 中的最长跳跃距离最小的大小
int n;
int vis[maxn];
double road[maxn][maxn];
int kase = 0;
struct node {
int x, y;
} p[maxn];
double get_dis(node a, node b) {
return sqrt(pow((double)(a.x-b.x), 2) + pow((double)(a.y-b.y), 2));
}
void dj() {
int v;
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) { // 初始化
d[i] = road[1][i];
}
vis[1] = 1;
for(int i = 2; i <= n; i++) { // 因为已经放进点1了所以这里这要再放n-1个点就行了
double mindis = inf;
for(int j = 1; j <= n; j++) {
if (!vis[j] && d[j] < mindis) {
mindis = d[j];
v = j;
}
}
vis[v] = 1;
for (int j = 1; j <= n; j++) {
if (!vis[j]) {
d[j] = min(d[j], max(d[v], road[v][j])); // 更新
}
}
}
printf("Scenario #%d\n", ++kase);
printf("Frog Distance = %.3lf\n\n", d[2]);
}
int main() {
//freopen("input.txt", "r", stdin);
while(~scanf("%d", &n) & n) {
for(int i = 1; i <= n; i++) {
scanf("%d%d", &p[i].x, &p[i].y);
}
for(int i = 1; i <= n; i++) {
for(int j = i; j <= n; j++) {
road[i][j] = road[j][i] = get_dis(p[i], p[j]);
}
}
dj();
}
return 0;
}