ACwing(基礎)--- Dijkstra演算法(含堆優化版)
阿新 • • 發佈:2020-07-04
樸素Dijkstra演算法
- 時間複雜是 O(n^2+m), n 表示點數,m 表示邊數
- 適合稠密圖
#include<cstring> #include<iostream> #include<algorithm> #define mm(a,x) memset(a,x,sizeof(a)) #define inf 0x3f3f3f3f using namespace std; const int maxn = 510; int n,m; int mp[maxn][maxn]; int dist[maxn]; int vis[maxn]; // 求1號點到n號點的最短路,如果不存在則返回-1 int dijkstra(){ mm(dist,0x3f);//初始化距離 0x3f代表無限大 dist[1]=0;//第一個點到自身的距離為0 for(int i=0;i<n;i++){ int t=-1; // 在還未確定最短路的點中,尋找距離最小的點 for(int j=1;j<=n;j++)//從一號點開始 if(!vis[j]&&(t==-1||dist[t]>dist[j])) t=j; vis[t]=1; // 用t更新其他點的距離 for(int j=1;j<=n;j++) dist[j]=min(dist[j],dist[t]+mp[t][j]); } if(dist[n]==inf) return -1;//如果第n個點路徑為無窮大即不存在最低路徑 return dist[n]; } int main(){ cin>>n>>m; mm(mp,0x3f); while(m--){ int a,b,c; cin>>a>>b>>c; mp[a][b]=min(mp[a][b],c); } int t=dijkstra(); cout<<t; return 0; }
堆優化版Dijkstra
- 時間複雜度為O(mlogn),n表示點數,m表示邊數
- 堆優化版的dijkstra是對樸素版dijkstra進行了優化
- 在樸素版dijkstra中時間複雜度最高的尋找距離最短的點O(n^2)可以使用最小堆優化。
- 一號點的距離初始化為零,其他點初始化成無窮大。
- 將一號點放入堆中。
- 不斷迴圈,直到堆空。每一次迴圈中執行的操作為:
彈出堆頂(與樸素版diijkstra找到S外距離最短的點相同,並標記該點的最短路徑已經確定)。
用該點更新臨界點的距離,若更新成功就加入到堆中。
時間複雜度分析
尋找路徑最短的點:O(n)
加入集合S:O(n)
更新距離:O(mlogn)
#include<iostream> #include<cstring> #include<queue> #include<algorithm> #define mm(a,x) memset(a,x,sizeof a) #define inf 0x3f3f3f3f using namespace std; typedef pair<int ,int > PII; const int maxn = 1e6+10; int n,m; int h[maxn],w[maxn],e[maxn],ne[maxn],idx; int dist[maxn],vis[maxn]; void add(int a,int b,int c) { e[idx] =b,w[idx]=c,ne[idx]=h[a],h[a]=idx++; } int dijkstra() { mm(dist,inf); dist[1]=0; priority_queue<PII,vector<PII>,greater<PII>> heap; // 定義一個小根堆 heap.push({0,1});// 這個順序不能倒,pair排序時是先根據first,再根據second,這裡顯然要根據距離排序 while(heap.size()) { auto t =heap.top();// 取不在集合S中距離最短的點 heap.pop(); int ver=t.second,distance = t.first; if(vis[ver]) continue; vis[ver]=1;//標記該點 for(int i = h[ver];i!=-1;i = ne[i]){ int j = e[i];// i只是個下標,e中在存的是i這個下標對應的點 if(dist[j] > distance + w[i]){ dist[j] = distance + w[i]; heap.push({dist[j],j});//放入堆中,更新其他點 } } } if(dist[n] == inf) return -1; return dist[n]; } int main() { scanf("%d%d",&n,&m); mm(h,-1); while(m--){ int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); } int t=dijkstra(); printf("%d\n",t); return 0; }