单源次短路
一、问题抽象
- 目的:求图中距离某点的第二短距离(大于或者等于最短距离)。
- 分类:
- 边可以重复经过
- 边不能重复经过
- 应用:求取备用线路,交通、路由等。
二、算法介绍
dijkstra优化
1.不可重复边
Introduction
dijkstra算法可以求出非负权图中距离原点的最短路径
pre[i]、距离dist[i]。只要去掉最短路径中的一条边,得出的距离一定比最短路径长。每次去掉最短路径中的一条边跑一遍dijkstra算法,这些dist[dest]中的最小值就是次短距离。
Pseudocode
# dijkstra(edge) 不经过edge这条边
# edges 最短路径边集
dijkstra(nullEdge) --> edges
secondary = INF
for edge in edges:
dijkstra(edge)
ans = min(ans, dist[dest])
C++ Demo 例题
#include <bits/stdc++.h>
using namespace std;
int n, m;
struct Vertex{
int x, y;
double dist;
int prev;
vector<int> post;
}vertex[201];
vector<vector<double> > edge(301, vector<double>(301, INT_MAX));
double distance(Vertex a, Vertex b){
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
void dijkstra(int x, int y){
//容器初始化
for(int i = 1; i <= n; i++){
vertex[i].dist = INT_MAX;
}
vector<bool> vis(n+1, false);
priority_queue<pair<double, int>, vector<pair<double, int> >, greater<pair<double, int> > > pq;
//初始节点入队
pq.push(make_pair(0, 1));
vertex[1].dist = 0;
//Dijkstra算法
while(!pq.empty()){
int u = pq.top().second;
pq.pop();
if(vis[u]) continue;
vis[u] = true;
for(int v :vertex[u].post){
if(u == x && v == y || u == y && v == x) continue;//skip(x, y)
if(vertex[v].dist > vertex[u].dist + edge[u][v]){
vertex[v].dist = vertex[u].dist + edge[u][v];
pq.push(make_pair(vertex[v].dist, v));
if(x == -1 && y == -1) vertex[v].prev = u;//record path
}
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> vertex[i].x >> vertex[i].y;
}
for(int i = 1; i <= m; i++){
int u, v;
cin >> u >> v;
edge[u][v] = edge[v][u] = distance(vertex[u], vertex[v]);
vertex[u].post.push_back(v);
vertex[v].post.push_back(u);
}
dijkstra(-1, -1);
double ans = INT_MAX;
for(int i = n; i != 1; i = vertex[i].prev){
dijkstra(i, vertex[i].prev);
ans = ans > vertex[n].dist ? vertex[n].dist : ans;
}
if(ans >= INT_MAX) cout << -1 << endl;
else cout << fixed << setprecision(2) << ans << endl;
return 0;
}
2.可重复边
Introduction
去掉访问标记,建立两个距离容器,存放最短距离与次短距离。
最短容器更新与原始一致,此短距离的更新:
a.最短距离更新时,赋旧值if dist_now + w < dist1[v] then dist2[v] = dist1[v]
b.距离D大于最短距离dist_now + w > dist1[v]并且小于次短距离dist_now + w < dist2[v]
Pseudocode
while pq:
u = pq.pop
for v next to u:
check for dist1
check for dist2
C++ Demo 例题
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-'){
w = -1;
}
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
int n, r;
vector<pair<int, int>> post[5001];
vector<int> dist1(5001, LLONG_MAX);
vector<int> dist2(5001, LLONG_MAX);
void dijkstra(int s){
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
dist1[s] = 0;
pq.push({0, s});
while(!pq.empty()){
int u = pq.top().second;
int dist_now = pq.top().first;
pq.pop();
if(dist_now > dist1[u] && dist_now > dist2[u]) continue;
for(auto post : post[u]){
int v = post.first;
int w = post.second;
if(dist_now + w < dist1[v]){
dist2[v] = dist1[v];
dist1[v] = dist_now + w;
pq.push({dist1[v], v});
}else if(dist_now + w < dist2[v] && dist_now + w > dist1[v]){
dist2[v] = dist_now + w;
pq.push({dist2[v], v});
}
}
}
}
signed main(){
cin >> n >> r;
for(int i = 1; i <= r; i++){
int x = read(), y = read(), w = read();
post[x].emplace_back(y, w);
post[y].emplace_back(x, w);
}
dijkstra(1);
cout << (dist2[n] == LLONG_MAX ? -1 : dist2[n]) << endl;
return 0;
}

浙公网安备 33010602011771号