基於C++的Dijkstra最短路徑演算法
阿新 • • 發佈:2019-02-18
#include "stdafx.h" #include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<iostream> #include<functional> using namespace std; const int maxn = 1e3; const int INF = 1e9; //int G[maxn][maxn];//鄰接表表示 int dis[maxn];//最短路 int vis[maxn] = { false };//標記頂點v是否已被訪問 int vertex, edge, start;//頂點,邊,起點 int pre[maxn];//pre[i]=u代表結點i的前驅為u int num[maxn] = { 0 };//記錄最短路徑條數 struct node{ int v; int routelen; }; vector<node> adjacent[maxn];//鄰接矩陣表示 void dijkstra(int start) {//Dijkstra演算法 fill(dis, dis + maxn, INF);//最短路徑初始化為無窮 fill(pre, pre + maxn, -1);//初始化前驅 dis[start] = 0; pre[start] = start; num[start] = 1; for (int i = 0; i < vertex; i++) {//迴圈n次 int u = -1, min = INF; for (int j = 0; j < vertex; j++) {//尋找還未被訪問頂點的最短路 if (dis[j] < min && vis[j] == false) { u = j; min = dis[j]; } } if (u == -1) return;//如果沒找到,則return vis[u] = true;//如果找到,則置u被訪問 for (int j = 0; j < adjacent[u].size(); j++) {//從u出發能夠到達的所有頂點 int v = adjacent[u][j].v; if (vis[v] == false) { if (dis[u] + adjacent[u][j].routelen < dis[v]) {//v未被訪問&&以u為中介點能夠使得dis[v]更短 dis[v] = dis[u] + adjacent[u][j].routelen;//更新路徑 pre[v] = u;//更新前驅 num[v] = num[u];//更新路徑條數 } else if (dis[u] + adjacent[u][j].routelen == dis[v]) {//此處一定要用else if語句,不能用if,否則得到的num不正確 num[v] += num[u];//更新路徑條數 } } } } } void dfs(int a[],int k) {//遞迴輸出最短路徑 if (a[k] == k) { printf("%d", k); } else if (a[k] == -1) { printf("無到達此點的路徑"); } else { dfs(a, a[k]);//遞迴輸出前驅結點 printf("->%d", k);//輸出本結點 } } int main() { //fill(G[0], G[0] + maxn * maxn, INF); scanf("%d%d%d", &vertex, &edge, &start); int s, e, value; for (int i = 0; i < edge; i++) { int start, end, weight; scanf("%d%d%d", &start, &end, &weight);//分別輸入起點,終點,邊權 node V; V.v = end;//v是邊的目標頂點 V.routelen = weight;//邊權 adjacent[start].push_back(V); } dijkstra(start); for (int i = 0; i < vertex; i++) {//輸出以start為源點,到達各大頂點的最短距離 printf("%d ", dis[i]); } putchar('\n'); int k; scanf("%d", &k);//輸入目標頂點k dfs(pre, k);//輸出源點到目標頂點k的最短路徑 printf("\n%d", num[k]);//輸出源點到目標頂點的最短路徑條數 return 0; }
執行結果如下:
注意:Dijkstra最短路經演算法的時間複雜度主要是由外層迴圈O(V)和內層迴圈尋找最小的d(U)需要的O(V)、列舉V需要的O(adjacent[U].size)產生的,所以時間複雜度是O(V方+E),現在採用堆進行優化(最簡潔的做法就是採用STL庫裡的優先佇列進行優化),使複雜度降為O(vlogv+E),即O(vlogv)
當然,採用鄰接表的話,時間複雜度達到了O(V方)
Dijkstra是用來求解無負權圖的單源最短路徑問題。如果要求解帶有負權圖的單源最短路徑,則需要採用Bellman-Ford或SPFA演算法,Bellman-Ford演算法講解請看下節: