【1】2020.05.21-00:36ios
1.完善dijkstra
【2】2020.05.21-11:25
1.完善dijkstra堆優化算法
在學習圖論算法的時候,最短路算法就是必學算法之一
那麼既然它這麼重要,就更須要咱們深刻了解,熟練掌握
默認圖爲連通圖學習
有點貪心動規的意思優化
這個問題只要你會存圖人就會作
(很像動態規劃對不對)spa
^RT,咱們要求出1-5的最短路徑
就必須求出起點到中轉點的最短路徑,中轉點爲4
想求出1-4的最短路徑,就先去求1-3的最短路徑
同理求1-2
而1-2的最短路就是其鏈接邊的權值3d
算法思路:code
定義變量(鏈式前向星的那堆變量就再也不重複寫了):
dis[i]
:表示從起點到i的最短距離
f[i]
:記錄這條邊有沒有被肯定過最短路
s
表示起點blog
初始化:dis[i]=∞;dis[s]=0
排序
遍歷每個點隊列
#include<iostream> using namespace std; #define NUM 500050 #define INF 2147483647 struct Edge{ int na,np,w; }e[NUM]; int head[NUM],dis[NUM],num,n,m,s,u,v,w,minn; bool f[NUM]; inline void add(int f,int t,int w){ e[++num].na=head[f]; e[num].np=t,e[num].w=w; head[f]=num; } int main(){ cin>>n>>m>>s; for(int i=0;i<m;i++){ cin>>u>>v>>w; add(u,v,w); } //初始化 for(int i=1;i<=n;i++) dis[i]=INF; dis[s]=0; //遍歷每個點 for(int i=1;i<=n;i++){ //對於每個點a,找到一個dis[b]最小的頂點b minn=-1; for(int o=1;o<=n;o++) if(f[o]==0&&(dis[minn]>dis[o]||minn==-1)) minn=o; //b被肯定過最短路 f[minn]=1; //遍歷全部以b爲起點的邊,更新它們的dis for(int o=head[minn];o!=0;o=e[o].na) if(!f[e[o].np]) dis[e[o].np]=min(dis[e[o].np],dis[minn]+e[o].w); } //算法結束,輸出s到各點的最短距離 for(int i=1;i<=n;i++) cout<<dis[i]<<" "; }
咱們能夠發現,對於原來的dijkstra算法,每次查找最小值時間複雜度都爲O(n)
那麼有什麼算法能夠在常數時間內求出最小值呢?
固然是(線段樹)堆啦!
創建一個小根堆,便可迅速求出全部數據的最小值
那麼咱們發現,對於每次掃描,會有一些數據已經肯定過最小值,再次進行掃描會浪費時間
因此咱們要使用隊列來實現
最終結論:用優先隊列+二元組實現
明白了這個以後,這道題對你來講+岩漿=黑曜石
#include<cstdio> #include<queue> #include<vector> #include<algorithm> using namespace std; #define ll int #define NUM 500050 #define INF 2147483647 struct Edge{ int na,np,w; }e[NUM]; ll head[NUM],dis[NUM],num,n,m,s,u,v,w,minn,bf,i; bool f[NUM]; priority_queue<pair<ll,ll>,vector<pair<ll,ll> >,greater<pair<ll,ll> > >q; inline void add(int f,int t,int w){ e[++num].na=head[f]; e[num].np=t,e[num].w=w; head[f]=num; } inline int read() { int X=0,W=1; char c=getchar(); while (c<'0'||c>'9') { if (c=='-') W=-1; c=getchar(); } while (c>='0'&&c<='9') X=(X<<3)+(X<<1)+c-'0',c=getchar(); return X*W; } int main(){ n=read();m=read();s=read(); for(i=0;i<m;++i){ u=read();v=read();w=read(); add(u,v,w); } for(int i=1;i<=n;++i) dis[i]=INF; dis[s]=0; //以上所有爲初始化 q.push(make_pair(0,s)); //將起點壓進隊列 while(q.size()){ //若是隊列裏還有元素 bf=q.top().second;q.pop(); //bf爲當前次遍歷的起點,保存後將這個元素彈出 if(f[bf]) continue; //搜過了就不搜了 f[bf]=1; //沒搜過就標記一下 for(int i=head[bf];i;i=e[i].na){ //一樣的遍歷 if(dis[bf]+e[i].w<dis[e[i].np]){ //找到了更短的路徑 dis[e[i].np]=dis[bf]+e[i].w; //更新 q.push(make_pair(dis[e[i].np],e[i].np)); //既然有更優解那就將這個點壓進隊列,用來更新其餘點 } } } for(int i=1;i<=n;++i) printf("%d ",dis[i]); //out }
那麼至於爲何make_pair的參數是最短距離,邊的終點呢?
爲何不反過來存或存其餘的參數呢
由於這是個自動排序的優先隊列啊
由於二元組自帶排序規則啊