單源點最短路徑Dijkstra和Bellmanford
阿新 • • 發佈:2018-11-26
單源點最短路徑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]);
}
}