这道题是求次短路径。做法比我想象的简单。思路和求最短路径基本一样,只是同时更新最短和次短路径,所以Dijkstra, SPFA等在这里依然可以用。这里用的是SPFA。
更新次短路径的逻辑已经比较复杂了。次短路径的来源可能是:
1. 该节点的最短路径。如果发现了新的最短路径,那么次短路径就是旧的最短路径。
2. 邻接节点的最短路径。邻接节点的最短路径加上一跳可能比该点的最短路径大,但可能比次短路径小。
3.邻接节点的次短路径。与上面类似,可能会发现该节点新的次短路径。
我猜如果问题求k短路径的时候上述更新逻辑已经过于复杂,有的解题报告中提到的A*可能是正确的做法。
测试数据:
5 10
1 2 1982
2 3 3963
3 4 2046
3 5 1353
4 2 1370
4 1 2192
5 3 2898
4 3 1395
4 1 3722
3 2 4596
(5591)
4 6
1 2 1
1 2 5
1 3 2
2 3 2
2 4 1
2 4 6
(4)
thestoryofsnow | 3255 | Accepted | 2588K | 219MS | C++ | 1781B |
/*
ID: thestor1
LANG: C++
TASK: poj3255
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>
using namespace std;
const int INF = 5000 * 5000;
class Edge
{
public:
int v, w;
Edge() {}
Edge(int v, int w) : v(v), w(w) {}
};
int main()
{
int N, R;
scanf("%d%d", &N, &R);
std::vector<vector<Edge> > adjs(N, std::vector<Edge>());
for (int r = 0; r < R; ++r) {
int A, B, D;
scanf("%d%d%d", &A, &B, &D);
A--, B--;
adjs[A].push_back(Edge(B, D));
adjs[B].push_back(Edge(A, D));
}
// Shortest-Path-Faster-Algorithm
// see https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm
vector<vector<int> > dis(N, vector<int>(2));
for (int i = 0; i < N; ++i) {
dis[i][0] = dis[i][1] = INF;
}
const int source = 0;
dis[source][0] = 0;
queue<int> que;
std::vector<bool> isInQueue(N, false);
que.push(source);
isInQueue[source] = true;
while (!que.empty()) {
int u = que.front();
que.pop();
isInQueue[u] = false;
for (int i = 0; i < adjs[u].size(); ++i) {
int v = adjs[u][i].v, w = adjs[u][i].w;
int nd = dis[u][0] + w;
bool updated = false;
if (nd < dis[v][0]) {
dis[v][1] = dis[v][0];
dis[v][0] = nd;
updated = true;
}
if (nd > dis[v][0] && nd < dis[v][1]) {
dis[v][1] = nd;
updated = true;
} else {
nd = dis[u][1] + w;
if (nd > dis[v][0] && nd < dis[v][1]) {
dis[v][1] = nd;
updated = true;
}
}
if (updated && !isInQueue[v]) {
que.push(v);
isInQueue[v] = true;
}
}
}
const int sink = N - 1;
printf("%d\n", dis[sink][1]);
return 0;
}