貪心策略之Dijkstra演算法
阿新 • • 發佈:2019-02-16
Dijkstra演算法是解決有向帶權圖中最短路徑的演算法。
我用自己的語言解釋Dijkstra演算法的過程:
1.首先有一個有向帶權圖G=(V,E),V為頂點集合,E為邊集合,用鄰接矩陣map[n][n]來儲存。
確定一個起始點origin,有一個輔助集合s,一開始將origin併入s中。
有一個輔助陣列dist[n],dist[i]表示i距離origin的最短距離,初始化dist[i]=map[origin][i]。若不存在弧則相應等於無窮大
2.找一個頂點j,使頂點j存在於V-s中(即頂點j屬於V但不屬於s),並且dist[j]是所有V-s頂點中最小的一個,將頂點j併入s中;
3.遍歷以頂點j為地點的弧<j,k>且k屬於V-s中,如果dist[k] > dist[j] + weight<j,k>,則令dist[k]=dist[j] + weight<j,k>;
這一步相當於搭一個頂點j的順風車。已知origin-j最短的距離是dist[j],若origin-k的(直接)距離大於
dist[j] + weight<j,k>,說明源點到頂點k的路徑可以通過頂點j這條路而減少距離。
4.重複2,3步,直到s中包含了V中所有的頂點,結束演算法。
程式碼:(C++實現)
#include <iostream> #define MAX 999999 using namespace std; const int n =5; //頂點數量 int map[n+1][n+1]; //有向圖 鄰接矩陣 int dist[n+1]={MAX}; //起點到其餘頂點的距離 int s[n+1]={0}; //頂點集合 int pre[n+1]={0}; //每個頂點的直接前驅 void findMin(int origin) { int i,j; for(j=1;j<=n;j++) { int minWeight=MAX; //dist[i]中最小權值 int minPoint =0; //最小權值的點 for(i=1;i<=n;i++) { if( !s[i] && dist[i]<= minWeight ) //尋找不在s中的最小權值的點 { minWeight = dist[i]; minPoint = i; } } if(minPoint==0) //如果沒有找到,說明所有頂點都以併入s中 return ; s[minPoint]=1; //將最小權值的點並中s中 //修改不在s中的其他頂點的dist值 for(i=1;i<=n;i++) { if( !s[i] && map[minPoint][i] != MAX) if(dist[i] > dist[minPoint] + map[minPoint][i]) { dist[i] = dist[minPoint] + map[minPoint][i]; pre[i] = minPoint; //將需要修改的頂點的直接前驅改為最小的權值點 } } } } void findPath(int i) { if(pre[i]==0) //表示i可能是起始點,也可能是和起始點不強連通的的點 { if(dist[i] != MAX) //起始點 cout<<i; else //與起始點不強連通的點 cout<<"不存在"; return ; } findPath(pre[i]); cout<<"-"<<i; } int main() { int i,j; int weight; int origin; //起點頂點 //鄰接矩陣初始化 for(i=1;i<=n;i++) for(j=1;j<=n;j++) map[i][j] = MAX; cout<<"請輸入權值"<<endl; cout<<"格式:i j weight"<<endl; cout<<"示例:1 2 2 即有一條弧<1,2>,權值為2,未輸入資料則預設為無窮大"<<endl; cout<<"結束時輸入 0 0 0"<<endl; cout<<"*************************"<<endl; while(1) { cin>>i>>j>>weight; if(i==0 && j==0 && weight==0) break; else map[i][j] = weight; } cout<<"請輸入起始點"<<endl; cin>>origin; //也可以通過遍歷鄰接矩陣找到入度為0的點找到源點 map[origin][origin]=0; /*初始化dist[]與pre[] *dist[]初始值為源點與其餘頂點i的權值,即map[origin][i],不存在弧則為無窮大MAX *pre[] 中,若其餘頂點i與源點有弧,則pre[i]=1,否則等於0 */ for(i=1;i<=n;i++) { dist[i]=map[origin][i]; if(map[origin][i] != MAX && map[origin][i] != 0) pre[i]=origin; } s[origin]=1;//初始化s[],即將源點加入s中 findMin(origin); /*輸出頂點的頂點的最短路徑*/ for(i=1;i<=n;i++) { cout<<"從起點"<<origin<<"去頂點"<<i<<"的最短路徑為:"; findPath(i); cout<<" 最短距離為:"<<dist[i]; cout<<endl; } return 0; }
實現示例:
例子1:
例子2: