题号:zoj 1942
解题思路
首先要读懂题目的要求,题目给出n个点,其中包含一个起点一个终点,其余n-2个点均有可能出现在由起点到终点的任意一条路径上。我们以这n个点任意两点之间的欧式距离为权值构造一个带权图。
然后是理解题目的概念“a frog’s jump”,任意一条从起点到终点的路径上权值最大的边对应的权值即为“a frog’s jump”。现在题目要求的就是起点到终点的所有路径的“a frog’s jump”的最大值。
题目整体的解法与求最短路径类似,我们可以用类似于以每个点为中转站,通过比较原距离与经过中转站后的距离的大小的方式,来对距离进行修改。基于这个想法,目前关键就是要找到修改距离的依据。
现有3个点,起点为1,终点为2,中转点为3,对应边权值如图。
现1->2,有两条路径,权值为{5},和{3,4},根据题目定义两条路径的“a frog’s jump”分别为5和4,按题意此时应进行距离的修改,也就是求max{5}和max{3,4}的最小值,由此转换依据为:
distance(a,b) = min(distance(a,b), max(distance(a,c), distance(c,b))
得到该表达式后使用求最短路径的通用算法即可求出结果,这里使用动态规划的方法
程序
#include<stdio.h>
#include<math.h>
#define N 205
using namespace std;
double min(int a, int b) {
if (a > b)return b;
return a;
}
double max(int a, int b) {
if (a > b)return a;
return b;
}
int a1[N], a2[N];
int map[N][N];
int n,x,y;
int main() {
int index = 0;
double result = 0;
while (1) {
index++;
scanf("%d", &n);
if (n == 0)break;
for (int i = 0; i < n; i++) {
scanf("%d%d", &x, &y);
a1[i] = x;
a2[i] = y;
}
for (int i = 0; i < n; i++) {
for (int k = i+1; k < n; k++) {
map[i][k] = map[k][i] = (a1[i] - a1[k])* (a1[i] - a1[k]) + (a2[i] - a2[k])* (a2[i] - a2[k]);
}
}
for (int p = 0; p < n; p++) {
for (int i = 0; i < n; i++) {
for (int k = 0; k < n; k++) {
map[i][k] = min(map[i][k], max(map[i][p], map[p][k]));
}
}
}
result = sqrt(map[0][1]);
printf("Scenario #%d\n", index);
printf("Frog Distance = %.3f\n\n", result);
}
return 0;
}
收获总结
这一道题目花了比较长的时间,首先因为不是很理解题目的要求,导致不清楚如何写出修改距离的条件,而找到这个条件就是本题目的关键。后来了解了题目的意思,即找出两点所有的路径对应最大边再对所有的最大边进行比较找出最小值,之后就明白可以用两点之间路径的最大边作为依据表示题目中的“距离”,并以此为依据进行距离的比较修改,题目后面的思路就比较容易展开了。
后面就是直接使用求最短路径的通用算法即可解决问题。本题可以使用dijkstra算法或者动态规划的算法来求最短路径,我使用了动态规划的算法。这里在补充一下dijkstra算法,比较的内容是出发点到另一点路径上最大边的长度,其他的基本与求最短路径一致。