P4779 【模板】单源最短路径(标准版)
# 【模板】單源最短路徑(標準版)
## 題目背景
2018 年 7 月 19 日,某位同學在 [NOI Day 1 T1 歸程](https://www.luogu.org/problemnew/show/P4768) 一題里非常熟練地使用了一個廣為人知的算法求最短路。
然后呢?
$100 \rightarrow 60$;
$\text{Ag} \rightarrow \text{Cu}$;
最終,他因此沒能與理想的大學達成契約。
小 F 衷心祝愿大家不再重蹈覆轍。
## 題目描述
給定一個 $n$ 個點,$m$ 條有向邊的帶非負權圖,請你計算從 $s$ 出發,到每個點的距離。
數據保證你能從 $s$ 出發到任意點。
## 輸入格式
第一行為三個正整數 $n, m, s$。
第二行起 $m$ 行,每行三個非負整數 $u_i, v_i, w_i$,表示從 $u_i$ 到 $v_i$ 有一條權值為 $w_i$ 的有向邊。
## 輸出格式
輸出一行 $n$ 個空格分隔的非負整數,表示 $s$ 到每個點的距離。
## 樣例 #1
### 樣例輸入 #1
```
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
```
### 樣例輸出 #1
```
0 2 4 3
```
## 提示
樣例解釋請參考 [數據隨機的模板題](https://www.luogu.org/problemnew/show/P3371)。
$1 \leq n \leq 10^5$;
$1 \leq m \leq 2\times 10^5$;
$s = 1$;
$1 \leq u_i, v_i\leq n$;
$0 \leq w_i \leq 10 ^ 9$,
$0 \leq \sum w_i \leq 10 ^ 9$。
本題數據可能會持續更新,但不會重測,望周知。
2018.09.04 數據更新 from @zzq
1.這個問題用dijkstra算法即可,要使用堆優化的dijkstra算法,否則會時間超限。
2.剛開始我是想自己手寫一個堆,模擬優先隊列,然而修修改改還是只是AC了倆個點 ,沒辦法去學了C++里面的STL里的優先隊列。
3.繼而就簡單多了(代碼少了將近一大半)
4.堆優化的dijkstra算法也是非常簡單,核心思想是一樣的,先松弛,再找最近的那一個點,繼續松弛循環下去。用堆來實現就是把新更新的距離權值入隊,然后在優先隊列里面會自動在首元素是最小值了。我們只需要判斷堆頂元素是否訪問過即可,如果訪問過了,就彈出堆頂元素,繼續找就可以。
while( !q.empty() )//如果隊列不為空,就需要繼續訪問{tmp = q.top();//訪問堆頂元素q.pop();//彈出隊頭x = tmp.pos, w = tmp.w;if( book[x] )continue;//如果該點已經納入最短路徑,需要跳過book[x] = 1;//從該點開始松弛for(i = head[x]; i; i = e[i].next )//鏈式前向星{y = e[i].to;if( dis[y] > dis[x] + e[i].w ){dis[y] = dis[x] + e[i].w;if( !book[y] ){q.push( ( node ){dis[y], y} );//插入元素并且重新排序}}}}完整C++代碼如下:
#include<iostream> #include<bits/stdc++.h> #include<cstdio> #include<algorithm>using namespace std;const int N = 100010, M = 500010; const int INF=1000000000; struct edges {int to;int w;int next; }e[M]; int head[N], dis[N]; bool book[N]; int n, m, s; struct node {int w;int pos;bool operator <( const node &x )const{return x.w <w;} }; priority_queue<node> q;//建立堆 void dijk() {int i,y,x,w;node tmp;dis[s] = 0;q.push( ( node ){0, s} );//放入該節點,也就是入隊while( !q.empty() )//如果隊列不為空,就需要繼續訪問{tmp = q.top();//訪問堆頂元素q.pop();//彈出隊頭x = tmp.pos, w = tmp.w;if( book[x] )continue;//如果該點已經納入最短路徑,需要跳過book[x] = 1;//從該點開始松弛for(i = head[x]; i; i = e[i].next )//鏈式前向星{y = e[i].to;if( dis[y] > dis[x] + e[i].w ){dis[y] = dis[x] + e[i].w;if( !book[y] ){q.push( ( node ){dis[y], y} );//插入元素并且重新排序}}}}for( i = 1; i <= n; i++ )printf( "%d ", dis[i] ); } int main() {int i,u,v,w;scanf( "%d%d%d", &n, &m, &s );for(i = 1; i <= n; i++) dis[i] =INF;for(i = 1; i <= m; i++){scanf( "%d%d%d", &u, &v, &w );e[i].to=v;e[i].w=w;e[i].next=head[u];head[u]=i;}dijk();return 0; }總結
以上是生活随笔為你收集整理的P4779 【模板】单源最短路径(标准版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [week13] TT的神秘礼物2
- 下一篇: 避不过裁员大潮,有钱任性也独木难支!以太