单源次短路

一、问题抽象

  • 目的:求图中距离某点的第二短距离(大于或者等于最短距离)。
  • 分类
    1. 边可以重复经过
    2. 边不能重复经过
  • 应用:求取备用线路,交通、路由等。

二、算法介绍

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;
}  

Reference:https://www.cnblogs.com/WiuehPlus/p/17620315.html

posted @ 2024-11-13 16:28  luvmis  阅读(50)  评论(0)    收藏  举报