\(dijkstra\)怎麼寫:首先,是和\(SPFA\)同樣的初始化。而後,把起點標記爲訪問。而後更新與其相連的點的最短路的值(就是鬆弛)。再找到未訪問的點中最短路的值最小的點,重複以上操做。
具體實現起來就是這個亞子:
(圖片來源於洛谷2019夏令營的課件)
講完基礎的,再來說一下細節問題:這個細節決定了時間複雜度!
這個細節就是「找到未訪問的點中最短路的值最小的點」。
兩種方法:
第一種:很是實用的爆掃。時間複雜度是O(\(n^2\)),我的感受和\(SPFA\)沒有什麼區別,不建議使用。
第二種:優先隊列!該方法是當一個點的最短路的值被更新後,就將其加入小根堆。這時小根堆裏會出現多個相同的點。可是咱們用過一個點以後就會將其標記,因此不會有問題。時間複雜度是O(mlogn)
什麼?你不知道小根堆是什麼?戳這裏
但咱們是不會手打小根堆的,太麻煩了。因而,咱們就要用到priority_queue
。他是系統自帶優先隊列,可是是大根堆。並且咱們是要按照每一個點的值來排序的。但咱們同時也要記錄他的編號。node
因而能夠這樣搞:spa
struct node { int first,second; friend bool operator<(node x,node y){return x.first>y.first;} }; priority_queue<node> q;
全部問題都解決了,那麼上代碼吧。code
#include<queue> #include<cstdio> #include<cstring> using namespace std; int n,m,s; int v[100005]; bool f[100005]; struct node { int first,second; friend bool operator<(node x,node y){return x.first>y.first;} }; priority_queue<node> q; struct graph { int tot; int hd[100005]; int nxt[200005],to[200005],dt[200005]; void add(int u,int v,int w) { tot++; nxt[tot]=hd[u]; hd[u]=tot; to[tot]=v; dt[tot]=w; return ; } }g; int main() { scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); g.add(u,v,w);//建圖 } memset(v,0x3f,sizeof(v));//初始化 q.push((node){0,s});//壓入起點 v[s]=0; while(!q.empty()) { int xx=q.top().second; q.pop(); if(!f[xx])//判斷是否被訪問過 { f[xx]=true;//標記一下 for(int i=g.hd[xx];i;i=g.nxt[i]) if(v[g.to[i]]>v[xx]+g.dt[i])//鬆弛 { v[g.to[i]]=v[xx]+g.dt[i]; q.push((node){v[g.to[i]],g.to[i]});//加入小根堆 } } } for(int i=1;i<=n;i++) printf("%d ",v[i]); return 0; }