知识点:最短瓶颈路,最小生成树,深搜
本题要求出起点和终点的最短瓶颈路,如果有多个求出其中最短路,最短瓶颈路就是两个点之间的简单路径的最大边权最小的路,它的求解可以用最小生成路来进行,求出最小生成树了,那么树上两点之间的路径就是最短瓶颈路,路径上边权的最大值就是我们要求的,这里可能有多个,所以我们先用最小生成树求出最短瓶颈路的值,然后在去求最短瓶颈路里面最短的,这里一看数据是100,就用了深搜去求最短路,效果还不错,但是一开始又犯了一个低级的错误,那就是没有个无向边的数组大小开够,浪费了快20分钟,然后这里其实就是只求了一对点最短瓶颈路的最大边长,如果要每一对点的就用个深搜记录搜索一下就行了
跑了40ms,还可以,要知道这还是在所有点建的边上跑的,并没有把不可能是最短瓶颈路的边给删掉
需要注意的是,输入的是先温度后距离,输出的时候是先距离后温度
#include <bits/stdc++.h>
using namespace std;
const int N = 105, M = 2e4 + 5;
struct edge {
int u, v;
double t, d;
edge() {}
edge(int a, int b, double x, double y): u(a), v(b), t(x), d(y) {}
};
int n, m, s, t, fa[N], vis[N];
int tot, ver[M], nxt[M], head[N];
double ans_t, ans_d, edge_t[M], edge_d[M];
edge e[N * N];
vector<int> v, ans;
void add(int x, int y, double z1, double z2) {
ver[++tot] = y;
edge_t[tot] = z1; edge_d[tot] = z2;
nxt[tot] = head[x]; head[x] = tot;
}
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
bool cmp(edge a, edge b) {
return a.t < b.t;
}
void dfs(int x, double dist) {
if (dist >= ans_d) return;
vis[x] = 1; v.push_back(x);
if (x == t) {
ans_d = dist;
ans = v;
vis[x] = 0; v.pop_back();
return;
}
for (int i = head[x]; i; i = nxt[i]) {
int y = ver[i];
if (!vis[y] && edge_t[i] <= ans_t) dfs(y, dist + edge_d[i]);
}
vis[x] = 0; v.pop_back();
}
int main() {
while (cin >> n >> m) {
tot = 0;
memset(head, 0, sizeof(head));
cin >> s >> t;
for (int i = 1; i <= m; i++) {
scanf("%d%d%lf%lf", &e[i].u, &e[i].v, &e[i].t, &e[i].d);
add(e[i].u, e[i].v, e[i].t, e[i].d);
add(e[i].v, e[i].u, e[i].t, e[i].d);
}
sort(e + 1, e + m + 1, cmp);
for (int i = 1; i <= n; i++) fa[i] = i;
int rec = 0;
ans_t = 0;
for (int i = 1; i <= m; i++) {
int x = get(e[i].u), y = get(e[i].v);
int ok1 = 0, ok2 = 0;
if (get(s) != get(t)) ok1 = 1;
if (x != y) {
fa[x] = y;
if (get(s) == get(t)) ok2 = 1;
if (ok1 && ok2) ans_t = e[i].t;
if (++rec == n - 1) break;
}
}
ans_d = 1e9;
dfs(s, 0);
int sz = (int) ans.size();
for (int i = 0; i < sz; i++) {
cout << ans[i] << (i < sz - 1 ? ' ' : '\n');
}
printf("%.1f %.1f\n", ans_d, ans_t);
}
return 0;
}