题解:[SDOI2009] Elaxia的路线
求给定无向图中两条最短路最长公共路径。
首先,最长公共路径一定是图上的一条链:假设不是一条链,而是分成两段,那么间隔两段的路径长度必然相同,否则不符合最短路的要求。而路径相同我们不妨就选择相同的一段路,这样仍为一条链。
因此,我们只需在两条最短路的任意一条最短路图上找与另一张图交的最长链即可。
构建最短路图可以用 Dijkstra,显然这个最短路图是一个 DAG,因此找最长交链可以用 DAG 上 DP 做,可以用 DFS 遍历所有在最短路图上的边。
然而,我们可能在 DP 过程中出现如下这种情况。

\(s'\to t'\) 有两种不同路径,但是在拓扑 DP 时会错误地判断两条不同路径形成一条链。我们只需对于两个图都跑一遍 DP 后取结果最小值即可。
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
const int N = 1510;
int n, m;
int u1, v1, u2, v2;
int deg[2][N];
ll d1[N], d2[N], f[N];
bool onmap[2][N][N], vis[N];
vector < pair <int, ll> > from[2][N];
vector < pair <int, ll> > g[N];
void dij (int s, ll* d, int id) {
for (int i = 0; i <= n; i ++) d[i] = 1e15;
d[s] = 0;
while (true) {
int u = 0;
for (int i = 1; i <= n; i ++) if (d[i] < d[u] && !vis[i]) u = i;
if (!u) break ;
vis[u] = true;
for (auto [v, w] : g[u]) {
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
from[id][v].clear ();
from[id][v].push_back ({u, w});
} else if (d[v] == d[u] + w) from[id][v].push_back ({u, w});
}
}
memset (vis, 0, sizeof vis);
}
void dfs (int u, int id) {
if (vis[u]) return ;
vis[u] = true;
for (auto [v, w] : from[id][u]) {
onmap[id][u][v] = onmap[id][v][u] = true;
++ deg[id][v];
dfs (v, id);
}
}
ll topsort (int s, int id) {
queue <int> q; q.push (s);
ll ans = 0;
while (!q.empty ()) {
int u = q.front (); q.pop ();
for (auto [v, w] : from[id][u]) {
-- deg[id][v];
if (onmap[id ^ 1][u][v]) f[v] = max (f[v], f[u] + w);
ans = max (ans, f[v]);
if (!deg[id][v]) q.push (v);
}
}
return ans;
}
int main (void) {
scanf ("%d%d", &n, &m);
scanf ("%d %d %d %d", &u1, &v1, &u2, &v2);
for (int i = 1, u, v, w; i <= m; i ++) {
scanf ("%d%d%d", &u, &v, &w);
g[u].push_back ({v, w});
g[v].push_back ({u, w});
}
dij (u1, d1, 0); dij (u2, d2, 1);
dfs (v2, 1); memset (vis, 0, sizeof vis); dfs (v1, 0);
printf ("%lld\n", min (topsort (v1, 0), topsort (v2, 1)));
return 0;
}

浙公网安备 33010602011771号