萬丈高樓平地起,勿在浮沙築高樓
阿新 • • 發佈:2019-01-03
題意:
給你一個圖,求次短路(路徑可以重複)。
思路:
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;
}