1. 程式人生 > >萬丈高樓平地起,勿在浮沙築高樓

萬丈高樓平地起,勿在浮沙築高樓

題意:
給你一個圖,求次短路(路徑可以重複)。
思路:
DJ同時進行最短路和次短路的更新。至於終止條件就是:它當前的最短距離小於該點標記的最短距離,說明該點已經取到最短距離,不進行操作。或者直接用一個vis陣列來記錄某一個點是否已經取到最短距離;其次的優化是用鄰接表儲存與每一個點相連的所有邊,方便處理。
具體看程式碼註釋。
推薦一個詳細的解釋:傳送門。

AC code:
#include<iostream>
#include<cstdio> 
#include<algorithm>
#include<queue>
using namespace
std; const int INF = 5e8; const int maxn = 5000 + 100; int n = 0,r = 0; struct edge{ int to; int cost; }; typedef pair<int,int> P; vector<edge> G[maxn];//鄰接表的正確姿勢,結構體儲存額外資訊,儲存邊而不是點(這樣便於寫結構體) int dist[maxn],dist2[maxn];//最短距離與次短距離 void solve(){ fill(dist,dist + maxn,INF); fill(dist2,dist2 + maxn,INF); dist[1
] = 0; priority_queue<P,vector<P>,greater<P> >que; que.push(P(1,0)); while(!que.empty()){ P p = que.top(); que.pop(); int v = p.first,d = p.second;//first是節點,second是對應的最短距離 if(dist2[v] < d){//如果條件成立,說明該點已經取到最短距離,d表示的是標記的距離,則不用更新了 continue
; //關鍵的終止條件,遍歷相鄰的點,更新相鄰點的dist和dist2,並且這些點會遍歷到以前遍歷過 //的點並且會將他放入優先佇列中,再次出對時就會判斷的,就會將它排除 //這裡比較難以理解,最好自己舉例理解 //比如從1->2->3->1 //這是比較兩者的dist,就是上面的那個條件,如果成立, } for(int i = 0;i < G[v].size();++i){//遍歷該節點的鄰接邊 edge e = G[v][i]; int d2 = e.cost + d; if(dist[e.to] > d2){//小於最短距離 swap(dist[e.to] , d2); que.push(P(e.to,dist[e.to])); dist2[e.to] = d2; que.push(P(e.to,dist2[e.to])); continue; } if(dist2[e.to] > d2 && dist[e.to] < d2){//處於最短距離和次短距離之間 dist2[e.to] = d2; que.push(P(e.to,dist2[e.to])); continue; } } } printf("%d\n",dist2[n]); } int main(){ while(scanf("%d %d",&n,&r) != EOF){ for(int i = 0;i < r;++i){ int a = 0,b = 0,c = 0; edge e; scanf("%d %d %d",&a,&b,&c); e.cost = c; e.to = b;G[a].push_back(e); e.to = a;G[b].push_back(e); } solve(); } return 0; }