1. 程式人生 > >單源點最短路徑Dijkstra和Bellmanford

單源點最短路徑Dijkstra和Bellmanford

單源點最短路徑Dijkstra和Bellmanford

Dijikstra演算法精髓在於維護了兩個集合s和v,而這也是實際程式設計中實現起來比較頭疼的事情,我的做法是把每個節點都設定成一個結構體,裡面有個狀態變數,為‘s’則意味著它在S集合當中。
另外還有很多小的細節需要注意
- 在C語言中實現時初始的鄰接矩陣表示(沒有的邊可以用很大的數來表示)
- 在鬆弛過程中注意不要侷限於在V集合中的那些點,在S集合中的點也有可能被鬆弛(但是這種情況只會出現在圖中有零環的情況,下面一個例子就是這樣的)
- 選取值最小的點。下例由於點數少,所以我直接兩個for迴圈找最小,如果圖大的話就要選用好的演算法了


程式碼塊

程式碼塊語法遵循標準markdown程式碼,例如:

#include<stdio.h>
#include<stdlib.h>
#define n 5
#define m 9999
//結構體陣列,node代表著一個結點,d為源點到此點的距離,state代表它是集合s中的還是v中的 
struct {
    int d;
    char state;
}node[n];
//鬆弛,代表把j加入到S後 應該做的一系列動作 
void relax(int j,int A[5][5]){
    for(int i=0;i<n;i++){
            if
((A[j][i]!=m)&&(node[j].d+A[j][i]<node[i].d)) {node[i].d=node[j].d+A[j][i];} } } int main() { //先初始化node[n]; int min,i,j; int s=0; node[0].d=0; node[0].state='v'; for(int i=1;i<n;i++){ node[i].d=m; node[i].state='v'; } int A[5
][5]={{m,-1,3,m,m},{m,m,3,2,2},{m,m,m,m,m},{m,1,5,m,m},{m,m,m,-3,m}}; //然後對d進行排序,把最小的那個state記作s,表示它不在鬆弛範圍內 while(s!=n){ //一直到所有的state為s為止 //下面兩個for是為了找到v中最小的那個 for(i=0;i<n;i++){ if(node[i].state=='v') { min=node[i].d; j=i; break; } } for(i=0;i<n;i++){ if((node[i].state=='v')&&(node[i].d<min) ) { min=node[i].d;j=i; } } //j目前記錄了最小的d值,下面把state變s,且把s集合的記錄數加1 node[j].state='s';s++; relax(j,A); } for(int i=0;i<n;i++){ printf("%d ",node[i].d); } //然後輸出陣列d[i];就是單元點A到各個點的最短路徑。

Bellmanford

#include<stdio.h>
#include<stdlib.h>
#define n 5
#define m 9999 
//Bellman-Ford演算法 
int main(){
    int t=1;
int A[5][5]={{m,-1,3,m,m},
  {m,m,3,2,2},
  {m,m,m,m,m},
  {m,1,5,m,m},
  {m,m,m,-3,m}}; 
   int d[n]={0,m,m,m,m};

  do{
   for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
        if(A[i][j]!=m) {
            if(d[j]>d[i]+A[i][j])
            d[j]=d[i]+A[i][j];
           }
       }


   }
   t++;
}while(t<=n-1);
for(int i=0;i<n;i++){
    printf("%d ",d[i]);
}
}