这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!
一、题目大意
题目的大致意思如下:处于某一个石头上的青蛙(男)想去找另一个石头上的青蛙(女),但由于两人的直接距离比较远,青蛙(男)无法直接跳过去,那么就需要经过一下中间的石头,多跳几次,来到达青蛙(女)所在的石头。我们把青蛙距离定义成最小的最长路,两个石头的青蛙距离就是对于两个石头之间的所有路径来说,它们的最长段中的最小值。可以给大家举一个例子。
比如对于这个图(有点丑,大家凑合看),顶点1和顶点2的青蛙距离就是6,怎么算的呢?从1到2有两个路径,1-3-4-2和1-5-2,在第一条路径中,其最长段为4-2,也就是6;在第二条路径中,其最长段为5-2,也就是8,两者的最小值就是6,也就是顶点1和顶点2的青蛙距离。相信看到这里,题目的意思应该很清楚了。
二、解题思路及AC代码
解这道题的思路就是用Dijkstra的变形,即将Dijkstra中的dist数组,dist[i]定义为从源到顶点 i 所有路径中最长段的最小值,那这样就需要重新考虑其选择和更新的问题,也就对应Dijkstra的选最小的dist和更新dist。
首先考虑更新,这样的一个dist数组要怎么更新呢?我们还是同以前一样,先假设每一步可以固定求解出一个dist数组中的值,那么设这个值为dist[x],那么我们接下来只需要对所有的顶点进行遍历,看哪一个顶点满足:dist[j] > max(dist[x], edges[x][j]),这个式子的意思就是说,因为x已经是确定的了,代表从源到顶点x的所有路径最长段的最小值,所以对于dist[j]的最长段最小值,要么就是dist[x],要么就是x到j的那条边的权值。(上述的j是遍历变量)
然后考虑选择。更新的问题已经解决了,就是说,我们如果已知dist[x]代表确定的最长段最小值,那么所有的dist都会得到正确的更新。现在就只需要考虑怎样得到最开始的dist[x]了,对于Dijkstra来说,最开始肯定是从dist[s]=0来开始更新的,那么我们只需要选择dist最小的作为开始的dist[x]就可以了,而且Dijkstra保证出现结果的单调性,只有这样我们才能进行后续的求解。
思路捋清楚啦! 下面给出代码的实现(Dijkstra和其heap优化):
Dijkstra:
#include <iostream>
#include <cmath>
#define MAXN 202
#define INF 10000000
using namespace std;
typedef pair <double, double> pp;
pp V[MAXN];
double edges[MAXN][MAXN];
double dist[MAXN];
bool vis[MAXN];
int n;
double Distance(double x1, double y1, double x2, double y2) {
return sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
}
double Max(double a, double b) {
return a > b ? a : b;
}
double Dijkstra(int s) {
for (int i = 0; i < MAXN; i++) {
dist[i] = INF;
vis[i] = false;
}
dist[s] = 0;
for (int i = 1; i <= n; i++) {
int min = INF; int x = -1;
for (int j = 1; j <= n; j++) {
if (!vis[j] && dist[j] < min) {
min = dist[x = j];
}
}
vis[x] = true;
for (int j = 1; j <= n; j++) {
if (!vis[j] && dist[j] > Max(dist[x], edges[x][j])) {
dist[j] = Max(dist[x], edges[x][j]);
}
}
}
return dist[2];
}
int main()
{
int Case = 0;
while (scanf("%d", &n) != EOF) {
Case++;
if (!n) break;
for (int i = 1; i <= n; i++) {
cin >> V[i].first >> V[i].second;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
double weight = Distance(V[i].first, V[i].second, V[j].first, V[j].second);
edges[i][j] = edges[j][i] = weight;
}
}
printf("Scenario #%d\n", Case);
printf("Frog Distance = %.3f\n\n", Dijkstra(1));
}
return 0;
}
Dijkstra + heap:
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
#define MAXN 202
#define INF 10000000
using namespace std;
int N;
typedef pair<int, double> pp;
typedef pair<double, double> ipp;
double edges[MAXN][MAXN];
double dist[MAXN];
bool vis[MAXN];
ipp V[MAXN];
struct cmp {
bool operator ()(pp a, pp b) {
return a.second > b.second;
}
};
double Distance(double x1, double y1, double x2, double y2) {
return sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
}
double Max(double a, double b) {
return a > b ? a : b;
}
double Dijkstra(int s) {
for (int i = 0; i < MAXN; i++) {
dist[i] = INF;
vis[i] = false;
}
priority_queue<pp, vector<pp>, cmp> pq;
pq.push(make_pair(s, 0));
dist[s] = 0;
while (!pq.empty()) {
int v = pq.top().first;
double d = pq.top().second;
pq.pop();
if (vis[v]) continue;
vis[v] = true;
for (int i = 1; i <= N; i++) {
if (!vis[i] && dist[i] > Max(dist[v], edges[v][i])) {
dist[i] = Max(dist[v], edges[v][i]);
pq.push(make_pair(i, dist[i]));
}
}
}
return dist[2];
}
int main()
{
int Case = 0;
while (scanf("%d", &N)) {
Case++;
if (!N) break;
for (int i = 1; i <= N; i++) {
cin >> V[i].first >> V[i].second;
}
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
double weight = Distance(V[i].first, V[i].second, V[j].first, V[j].second);
edges[i][j] = edges[j][i] = weight;
}
}
printf("Scenario #%d\n", Case);
printf("Frog Distance = %.3f\n\n", Dijkstra(1));
}
return 0;
}