大致题意
求有 N 个路口,R 条长度为 D 的双向路径的图中次短路的长度。1 ≤ N ≤ 5000, 1 ≤ R ≤ 100,000, 1 ≤ D ≤ 5000
到某个顶点 v 的次短路要么是到其他某个顶点 u 的最短路再加上 u -> v 的边,要么是到 u 的次短路再加上 u -> v 的边,因此所需要求的就是到所有顶点的最短路和次短路。因此,对于每个顶点,我们记录的不仅仅是最短距离,还有次短的距离。接下去只要用与 dijkstra 算法相同的做法,不断更新这两个距离就可以求出次短路了。
用堆来维护更新的距离,对于求最短路而言,可以使用 used 数组做记录,一旦某顶点已确定最短距离,就排除之后出队的该节点,因为该节点无法再松弛后续节点。
if(used[v]) continue;
此时,可以不使用以保存已确定最短距离节点的数组 used 来节省空间:通过判断当前出队的该顶点的路径长度与当前保存的最短路径长度做比较,若大于当先保存的最短路径,则说明该顶点已经被更新过。
if(dist[v] < cost) continue;
对于次短路而言,可以用同样的方法来节省空间。即当前出队的顶点路径值大于次短路目前保存的最小值时,说明该顶点的最短路和次短路已经被更新过。对于次短路,这种方法效率会低一些,而且在某些情况并不适用,如 POJ 3463 统计最短路和次短路的数量 。
#include <cstdio>
#include <STDLIB.H>
#include <algorithm>
#include<functional>
#include <queue>
#include <vector>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define abs(x) ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define eps 1e-4
#define M_PI 3.14159265358979323846
#define MAX_E 100000
#define MAX_V 5000
using namespace std;
typedef pair<int, int> P;
struct edge{
int to, cost;
edge(int to, int cost) : to(to), cost(cost) {}
};
int V, E;
vector<edge> G[MAX_V];
int dist[MAX_V][2];
int dijkstra(){
priority_queue<P, vector<P>, greater<P> > que;
memset(dist, 0x3f, sizeof(dist));
dist[0][0] = 0;
que.push(P(0, 0));
while(!que.empty()){
P p = que.top(); que.pop();
int v = p.second, cost = p.first;
if(cost > dist[v][1]) continue;
for(int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
int u = e.to, d = cost + e.cost;
if(d < dist[u][0]){
swap(d, dist[u][0]);
que.push(P(dist[u][0], u));
}
if(d < dist[u][1] && d > dist[u][0]){
dist[u][1] = d;
que.push(P(dist[u][1], u));
}
}
}
return dist[V - 1][1];
}
int main(){
while(~scanf("%d%d", &V, &E)){
for(int i = 0; i < V; i++) vector<edge> ().swap(G[i]);
for(int i = 0; i < E; i++){
int a, b, d;
scanf("%d%d%d", &a, &b, &d);
--a, --b;
G[a].push_back(edge(b, d));
G[b].push_back(edge(a, d));
}
printf("%d\n", dijkstra());
}
return 0;
}