單源最短路徑--貪心演算法
阿新 • • 發佈:2019-01-05
一個點(源點)到其餘各個頂點的最短路徑。也叫做“單源最短路徑”Dijkstra。
Dijkstra的主要思想:每次找到離源點最近的一個頂點,然後以該頂點為中心進行擴充套件,最終得到源點到其餘所有點的最短路徑
用flag標示該點是否在離源點最近的集合中
演算法步驟:
1.初始時,S只包含源點,即P={v},v的距離為0。U包含除v外的其他頂點,即:Q={其餘頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
2.從U中選取一個距離v最小的頂點k,把k,加入P中(該選定的距離就是v到k的最短路徑長度)。
3.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。
4.重複步驟2和3直到所有頂點都包含在P中
時間複雜度是O(N^2)。其中每次找到離1號頂點最近的頂點的時間複雜度是O(N),這裡可以用“堆”來優化使降低到O(logN),
另外對於邊數M少於N^2的稀疏圖來說(M<<N^2的圖稱為稀疏圖,而M較大的圖稱為稠密圖),我們可以用鄰接表來代替鄰接矩陣儲存,使得整個時間複雜度優化到O(N+M)logN。
結果:
Dijkstra的主要思想:每次找到離源點最近的一個頂點,然後以該頂點為中心進行擴充套件,最終得到源點到其餘所有點的最短路徑
用flag標示該點是否在離源點最近的集合中
演算法步驟:
1.初始時,S只包含源點,即P={v},v的距離為0。U包含除v外的其他頂點,即:Q={其餘頂點},若v與U中頂點u有邊,則<u,v>正常有權值,若u不是v的出邊鄰接點,則<u,v>權值為∞。
2.從U中選取一個距離v最小的頂點k,把k,加入P中(該選定的距離就是v到k的最短路徑長度)。
3.以k為新考慮的中間點,修改U中各頂點的距離;若從源點v到頂點u的距離(經過頂點k)比原來距離(不經過頂點k)短,則修改頂點u的距離值,修改後的距離值的頂點k的距離加上邊上的權。
4.重複步驟2和3直到所有頂點都包含在P中
時間複雜度是O(N^2)。其中每次找到離1號頂點最近的頂點的時間複雜度是O(N),這裡可以用“堆”來優化使降低到O(logN),
另外對於邊數M少於N^2的稀疏圖來說(M<<N^2的圖稱為稀疏圖,而M較大的圖稱為稠密圖),我們可以用鄰接表來代替鄰接矩陣儲存,使得整個時間複雜度優化到O(N+M)logN。
在最壞的情況下M就是N^2,這樣的話(N+M)logN要比N^2還要大,但是大多數情況下並不會有那麼多邊,因此(M+N)logN要比N^2小很多。
C++實現:
#include<iostream> using namespace std; int main() { int edgs; int points; int dis[10]; int flag[10]; int infinity = 9999999; cin>>points>>edgs; int edg[10][10]; //初始化有向圖的邊 for(int i=1;i<=points;i++) { for(int j=1;j<=points;j++) { if(i==j) { edg[i][j]=0; } else { edg[i][j]=infinity; } } } //給有向圖的邊賦權值 int point1,point2,quanzhi; for(i=1;i<=edgs;i++) { cin>>point1>>point2>>quanzhi; edg[point1][point2]=quanzhi; } for(i=1;i<=points;i++) { dis[i]=edg[1][i]; } //設定標記,對訪問過的頂點i賦予flag[i]=1,沒訪問的i賦予flag[i]=0 for(i=1;i<=points;i++) { flag[i]=0; } flag[1]=1; int min,u; //核心演算法 for(i=1;i<=points;i++) { min=infinity; for(int j=1;j<points;j++)//源點到源點不用比較,總的迴圈次數少一次 { if(flag[j]==0&&dis[j]<min)//核心思想:依次比較出離源點最近的點 { min=dis[j]; u=j; } } flag[u]=1; //找出離源點最近的點後開始更新dis裡面的源點到各個點的值是否最小 for(int v=1;v<=points;v++) { if(edg[u][v]<infinity) { if(dis[v]>dis[u]+edg[u][v]) //dis[1][v] 主要是找出離源點最近點的出邊來比較 { dis[v]=dis[u]+edg[u][v]; } } } } for(i=1;i<=points;i++) { cout<<dis[i]<<" "; } cout<<endl; }
結果: