單源最短路徑---Dijkstra算法
1、dijkstra算法求解過程:
(1)首先設置兩個頂點集合T和S
S中存放已找到最短路徑的頂點,初始時,集合S中只有一個頂點,即源點v0
T中存放當前還未找到最短路徑的頂點
(2)在集合T中選取當前長度最短的一條最短路徑(v0......vk),從而將vk加入到頂點集合S中,並修改遠點v0到T中各個頂點的最短路徑長度;重復這一步驟,直至所有點加入S為止。
2、算法實現
dist[n]:dist[i]表示當前找到的從源點v0出發到終點vi的最短路徑的長度,初始化時,dist[i] = edge[v0][i]
S[n]:S[i]為0表示頂點vi還未加入到集合S中,初始化時S[v0]=1,其余為0
path[n]:path[i]表示v0到vi的最短路徑上頂點vi的前一個頂點序號。采用“倒向追蹤”方法,確定v0到vi的最短路徑上的每個頂點
初始化:dist[k] = edge[v0][k]v0是源點S[v0]=1
遞推:
u = min{dist[t]}s[vt] = 0;
u表示當前T集合中dist數組元素值最小的頂點的序號,以後u加入集合S。
dist[k] = min(dist[k], dist[u] + edge[u][k])S[vk] = 0;
https://blog.csdn.net/qq_35644234/article/details/60870719
3.代碼實現:
輸入:
6 9
0 2 5
0 3 30
1 0 2
1 4 8
2 5 7
2 1 15
4 3 4
5 3 10
5 4 18
輸出:
從0到1距離是:20 0->2->1
從0到2距離是: 5 0->2
從0到3距離是:22 0->2->5->3
從0到4距離是:28 0->2->1->4
從0到5距離是:12 0->2->5
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6#include<queue> 7 #include<stack> 8 #include<map> 9 #include<sstream> 10 using namespace std; 11 typedef long long ll; 12 const int maxn = 1e3 + 10; 13 const int INF = 1 << 30; 14 int T, n, m; 15 int Map[maxn][maxn];//鄰接矩陣存圖 16 int v[maxn];//v[i] = 1表示已加入集合S 17 int d[maxn];//dist[i]表示距離源點的最短距離 18 int path[maxn];//記錄路徑 19 void dijkstra(int u0)//求頂點為u到其他頂點的最短路 20 { 21 memset(v, 0, sizeof(v)); 22 for(int i = 0; i < n; i++)d[i] = (i == u0 ? 0 : INF); 23 for(int i = 0; i < n; i++)path[i] = -1; 24 for(int i = 0; i < n; i++)//每次加入一個節點,循環n次 25 { 26 int x, m = INF; 27 for(int y = 0; y < n; y++)if(!v[y] && d[y] <= m)m = d[x = y];//記錄當前最小值 28 v[x] = 1;//標記已經加入集合 29 for(int y = 0; y < n; y++) 30 { 31 if(d[y] > d[x] + Map[x][y])//松弛操作 32 { 33 d[y] = d[x] + Map[x][y]; 34 path[y] = x; 35 } 36 } 37 } 38 for(int i = 0; i < n; i++) 39 { 40 if(i == u0)continue; 41 printf("從%d到%d距離是:%2d ", u0, i, d[i]); 42 stack<int>q; 43 int x = i; 44 while(path[x] != -1) 45 { 46 q.push(x); 47 x = path[x]; 48 } 49 cout<<u0; 50 while(!q.empty()) 51 { 52 cout<<"->"<<q.top(); 53 q.pop(); 54 } 55 cout<<endl; 56 } 57 } 58 int main() 59 { 60 cin >> n >> m; 61 for(int i = 0; i < n; i++) 62 { 63 for(int j = 0; j < n; j++) 64 { 65 if(i == j)Map[i][j] = 0; 66 else Map[i][j] = INF; 67 } 68 } 69 int x, y, z; 70 for(int i = 0; i < m; i++) 71 { 72 cin >> x >> y >> z; 73 Map[x][y] = z; 74 } 75 dijkstra(0); 76 return 0; 77 }
上述代碼時間復雜度O(n2),這裏可以將求最小值用優先隊列優化,時間復雜度降低到了O(nlog(n)),下面用結構體將其封裝起來
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<map> #include<sstream> using namespace std; typedef long long ll; const int maxn = 1e3 + 10; const int INF = 1 << 30; int T, n, m; struct edge { int from, to, dist; edge(int u, int v, int d):from(u), to(v), dist(d){} edge(){} }; struct Heapnode { int d, u;//d為距離,u為起點 Heapnode(){} Heapnode(int d, int u):d(d), u(u){} bool operator <(const Heapnode & a)const { return d > a.d;//這樣優先隊列先取出d小的 } }; struct Dijkstra { int n, m; vector<edge>edges;//存邊的信息 vector<int>G[maxn];//G[i]表示起點為i的邊的序號集 bool v[maxn];//標記點是否加入集合 int d[maxn];//起點s到各個點的最短路 int p[maxn];//倒敘記錄路徑 Dijkstra(){} void init(int n) { this -> n = n; for(int i = 0; i < n; i++)G[i].clear(); edges.clear(); } void addedge(int from, int to, int dist) { edges.push_back(edge(from, to, dist)); m = edges.size(); G[from].push_back(m - 1);//存以from為起點的下一條邊 } void dijkstra(int s)//以s為起點 { priority_queue<Heapnode>q; for(int i = 0; i < n; i++)d[i] = INF; d[s] = 0; memset(v, 0, sizeof(v)); memset(p, -1, sizeof(p)); q.push(Heapnode(0, s)); while(!q.empty()) { Heapnode now = q.top(); q.pop(); int u = now.u;//當前起點 if(v[u])continue;//如果已經加入集合,continue v[u] = 1; for(int i = 0; i < G[u].size(); i++) { edge& e = edges[G[u][i]];//引用節省代碼 if(d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i];//記錄e.to前的邊的編號 q.push(Heapnode(d[e.to], e.to)); } } } } void output(int u) { for(int i = 0; i < n; i++) { if(i == u)continue; printf("從%d到%d距離是:%2d ", u, i, d[i]); stack<int>q;//存的是邊的編號 int x = i;//x就是路徑上所有的點 while(p[x] != -1) { q.push(x); x = edges[p[x]].from;//x變成這條邊的起點 } cout<<u; while(!q.empty()) { cout<<"->"<<q.top(); q.pop(); } cout<<endl; } } }; Dijkstra ans; int main() { cin >> n >> m; ans.init(n); for(int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; ans.addedge(u, v, w); } int u = 0; ans.dijkstra(u); ans.output(u); }
單源最短路徑---Dijkstra算法