廣度優先搜索,開一個額外的數組存儲每個結點的訪問狀態,一層一層(取出隊首元素,遍歷全部相鄰且未被訪問的結點)的入隊列,而後層數++ios
這裏的額外數組就是dist[w],指的是從源點到頂點w的最短路徑長度,初始化爲-1,判斷未訪問即==-1,若是未訪問且存在邊G[v][w]
則dist[w] = dist[v] +1 ;算法
path數組用於保存每個頂點w的前驅頂點v,也即這條最短路徑(s->w)一定是從(s->....->v->w),經過棧來逆序輸出path[w] 、path[path[w]]....數組
更加詳細的算法示例能夠參考視頻ide
#include<iostream> #include<stdlib.h> #include<cstdlib> #include<queue> #include<stack> #define Init -1 #define MaxVertex 100 int path[MaxVertex]; // 存儲路徑,若是當前頂點v出隊列,且存在頂點v->w的路徑,則path[w] = v int dist[MaxVertex]; // 存儲路徑長度,即從源頂點s到當前頂點w的最短路徑dist[w] int G[MaxVertex][MaxVertex]; // 圖,採用鄰接矩陣表示 int Ne; // 頂點數 int Nv; // 邊 typedef int Vertex; using namespace std; void build(){ int v1,v2; // 初始化點 cin>>Nv; for(int i=1;i<=Nv;i++) for(int j=1;j<=Nv;j++) G[i][j] = 0; // 初始化路徑 for(int i=1;i<=Nv;i++) path[i] = Init; // 初始化路徑長度 for(int i=1;i<=Nv;i++) dist[i] = Init; // 初始化邊 cin>>Ne; for(int i=0;i<Ne;i++){ cin>>v1>>v2; G[v1][v2] = 1; // 有向圖! } } void Unweighted(Vertex v){ queue<Vertex> q; dist[v] = 0; // 將本身的距離置 0 ,路徑path[v]不變 Vertex w; q.push(v); while(!q.empty()){ w = q.front(); q.pop(); for(int i=1;i<=Nv;i++) // 若是沒被訪問過,且連通 if(dist[i]==Init && G[w][i]){ dist[i] = dist[w]+1; // 是上一步的距離 + 1 path[i] = w; // w 是上一步要走路徑的下一步路徑 q.push(i); } } } // 獲取路徑 void getTail(Vertex v){ for(int i=1;i<=Nv;i++){ if(i==v) continue; stack<Vertex> s; cout<<v<<"到"<<i<<"的最短距離是:"<<dist[i]; Vertex w = i; // 當沒到達起始起點前一直作循環 while(path[w]!=Init){ s.push(w); // 入棧 w = path[w]; } // 逆序輸出入棧元素,獲得路徑 cout<<" 其路徑爲:"; if(v != i) cout<<v; while(!s.empty()){ // 輸出棧頂元素 cout<<"→"<<s.top(); s.pop(); // 出棧 } cout<<endl; } } int main(){ build(); Unweighted(3); getTail(3); return 0; }
有權圖的單源最短路算法可使用Dijkstra算法實現,Dijkstra算法的基本思想是對圖G(V,E)設置集合S,存放已被訪問的頂點,而後每次從集合V-S中選擇與起點s的最短距離最小的一個頂點(記爲u),訪問並加入集合S。以後,令頂點u爲中間點,優化全部起點s經過點u可以到達的鄰接點v之間的最短路徑。這樣的操做執行n次,直到集合S已包含全部頂點。優化
算法的僞碼描述以下:ui
void Dijkstra( Vertex s ) { while (1) { V = 未收錄頂點中dist最小者; if ( 這樣的V不存在) break; collected[V] = true; for ( V 的每一個鄰接點W ) if ( collected[W] == false ) if ( dist[V]+E<V,W> < dist[W] ) { dist[W] = dist[V] + E<V,W> ; path[W] = V; } } } /* 不能解決有負邊的狀況*/
引出了兩個問題:spa
如何肯定未收錄頂點中dist最小者?3d
1.直接掃描全部未收錄頂點,時間複雜度爲– O( |V| ),總的時間複雜度爲T = O( |V|^2 + |E| )對於稠密圖效果好code
2.將dist存在最小堆中,時間複雜度爲– O( log|V| ),總的時間複雜度爲T = O( |V| log|V| + |E| log|V| ) = O( |E| log|V| ),對於稀疏圖效果好。視頻
如何初始化dist[i]?
G[0][w]
,則dist[w]能夠直接初始化爲頂點s到頂點w的邊權對於算法的詳細示例能夠參考視頻
#include<iostream> #include<stdlib.h> #define Inf 1000000 #define Init -1 #define MaxVertex 100 typedef int Vertex; int G[MaxVertex][MaxVertex]; int dist[MaxVertex]; // 距離 int path[MaxVertex]; // 路徑 int collected[MaxVertex]; // 被收錄集合 int Nv; // 頂點 int Ne; // 邊 using namespace std; // 初始化圖信息 void build(){ Vertex v1,v2; int w; cin>>Nv; // 初始化圖 for(int i=1;i<=Nv;i++) for(int j=1;j<=Nv;j++) G[i][j] = 0; // 初始化路徑 for(int i=1;i<=Nv;i++) path[i] = Init; // 初始化距離 for(int i=0;i<=Nv;i++) dist[i] = Inf; // 初始化收錄狀況 for(int i=1;i<=Nv;i++) collected[i] = false; cin>>Ne; // 初始化點 for(int i=0;i<Ne;i++){ cin>>v1>>v2>>w; G[v1][v2] = w; // 有向圖 } } // 初始化距離和路徑信息 void crate(Vertex s){ dist[s] = 0; collected[s] = true; for(int i=1;i<=Nv;i++) if(G[s][i]){ dist[i] = G[s][i]; path[i] = s; } } // 查找未收錄頂點中dist最小者 Vertex FindMin(Vertex s){ int min = 0; // 以前特意把 dist[0] 初始化爲正無窮 for(Vertex i=1;i<=Nv;i++) if(i != s && dist[i] < dist[min] && !collected[i]) min = i; return min; } void Dijkstra(Vertex s){ crate(s); while(true){ Vertex V = FindMin(s); // 找到 if(!V) break; collected[V] = true; //收錄 for(Vertex W=1;W<=Nv;W++) if(!collected[W] && G[V][W]){ // 若是未被收錄 if(dist[V] + G[V][W] < dist[W]){ dist[W] = G[V][W] + dist[V]; path[W] = V; } } } } void output(){ for(int i=1;i<=Nv;i++) cout<<dist[i]<<" "; cout<<endl; for(int i=1;i<=Nv;i++) cout<<path[i]<<" "; cout<<endl; } int main(){ build(); Dijkstra(1); output(); return 0; }
#include<iostream> #include<stdlib.h> #define INF 1000000 #define MaxVertex 100 typedef int Vertex; int G[MaxVertex][MaxVertex]; int dist[MaxVertex][MaxVertex]; // 距離 int path[MaxVertex][MaxVertex]; // 路徑 int Nv; // 頂點 int Ne; // 邊 using namespace std; // 初始化圖信息 void build(){ Vertex v1,v2; int w; cin>>Nv; // 初始化圖 for(int i=1;i<=Nv;i++) for(int j=1;j<=Nv;j++) G[i][j] = INF; cin>>Ne; // 初始化點 for(int i=0;i<Ne;i++){ cin>>v1>>v2>>w; G[v1][v2] = w; G[v2][v1] = w; } } void Floyd(){ for(Vertex i=1;i<=Nv;i++) for(Vertex j=1;j<=Nv;j++){ dist[i][j] = G[i][j]; path[i][j] = -1; } for(Vertex k=1;k<=Nv;k++) for(Vertex i=1;i<=Nv;i++) for(Vertex j=1;j<=Nv;j++) if(dist[i][k] + dist[k][j] < dist[i][j]){ dist[i][j] = dist[i][k] + dist[k][j]; path[i][j] = k; } } void output(){ for(Vertex i=1;i<=Nv;i++){ for(Vertex j=1;j<=Nv;j++) cout<<dist[i][j]<<" "; cout<<endl; } cout<<endl; for(Vertex i=1;i<=Nv;i++){ for(Vertex j=1;j<=Nv;j++) cout<<path[i][j]<<" "; cout<<endl; } } int main(){ build(); Floyd(); output(); return 0; }
更多詳細的算法描述請參考視頻
以及文章