题意
给出一张图,求出从点111到点nnn的次短路径。
思路
分别以起点和终点跑一次最短路,然后枚举一条边来绕长最短路变成次短路,更新答案。
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
int n, m, tot = -1, p, ans;
int ver[100001], next[100001], head[100001], edge[100001];
int dis[10001], dise[10001], v[10001];
void add(int u, int v, int w) {
ver[++tot] = v;
next[tot] = head[u];
edge[tot] = w;
head[u] = tot;
}
void spfa() {
memset(dis, 127 / 3, sizeof(dis));
std::queue<int> q;
q.push(1);
v[1] = 1;
dis[1] = 0;
while (q.size()) {
int x = q.front();
q.pop();
v[x] = 0;
for (int i = head[x]; ~i; i = next[i]) {
int y = ver[i];
if (dis[x] + edge[i] < dis[y]) {
dis[y] = dis[x] + edge[i];
if (!v[y]) {
v[y] = 1;
q.push(y);
}
}
}
}
}
void spfaa() {
memset(v, 0, sizeof(v));
memset(dise, 127 / 3, sizeof(dise));
std::queue<int> q;
q.push(n);
v[n] = 1;
dise[n] = 0;
while (q.size()) {
int x = q.front();
q.pop();
v[x] = 0;
for (int i = head[x]; ~i; i = next[i]) {
int y = ver[i];
if (dise[x] + edge[i] < dise[y]) {
dise[y] = dise[x] + edge[i];
if (!v[y]) {
v[y] = 1;
q.push(y);
}
}
}
}
}
int main() {
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(x, y, z);
add(y, x, z);
}
scanf("%d", &p);
spfa();
if (!p) printf("%d", dis[n]);
else {
ans = 2147483647;
spfaa();
for (int i = 0; i <= tot; i += 2) {
int x = ver[i ^ 1];
int y = ver[i];
int s = dis[x] + dise[y] + edge[i];
if (s > dis[n]) ans = std::min(ans, s);
s = dis[y] + dise[x] + edge[i];
if (s > dis[n]) ans = std::min(ans, s);
}
printf("%d", ans);
}
}
本文详细解析了求解从特定起点到终点的次短路径问题的算法思路,通过两次最短路径搜索结合边的枚举,高效地找到次优解。适用于图论和算法竞赛的学习者。

被折叠的 条评论
为什么被折叠?



