在有向圖 G=(V,E) 中,假設每條邊 E[i] 的長度為 w[i],找到由頂點 V0 到其余各點的最短值。
#include<stdio.h> #include<stdlib.h> #define max1 10000000 //原詞條這里的值太大,導致溢出,后面比較大小時會出錯 int a[1000][1000]; int d[1000];//d表示源節點到該節點的最小距離 int p[1000];//p標記訪問過的節點 int i, j, k; int m;//m代表邊數 int n;//n代表點數 int main() { // 實例中的數組實際上從1開始有意義 // 數組中的第0個元素沒有使用 scanf("%d%d",&n,&m); int min1; int x,y,z; for(i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); a[x][y]=z; a[y][x]=z; } // 為每個節點賦值(距離初始化為正無窮) for( i=1; i<=n; i++) d[i]=max1; // 1表示初始頂點,因此1到自己的距離是0 d[1]=0; // 循環n次,把n個頂點依次標記(計算出真實d值后標記) // 每次循環計算若干頂點的d值,但一部分計算的d值不是最終的,而是過渡值(注1) // 且每次循環處理的頂點是離初始點越來越遠的(d值越來越大) // 算法思想就是由近及遠確定每個點的最短值 for(i=1;i<=n;i++) { // 找出最近的點(循環從距離0的初始頂點開始) // 並標記(此后的循環不再討論該頂點) // 依據該頂點,重新計算出每個頂點的距離(試圖得到更小的距離) min1 = max1; //下面這個for循環的功能類似冒泡排序,目的是找到未訪問節點中d[j]值最小的那個節點, //作為下一個訪問節點,用k標記 for(j=1;j<=n;j++) if(!p[j]&&d[j]<min1) { min1=d[j]; k=j; } //置1表示第k個節點已經訪問過了 p[k] = 1; // 對於2級循環中的頂點j // 若j已經標記過,那么j必然已經計算出了d[j]最小路徑 // 若j計算得到了更優的距離d[j]>d[k]+a[k][j] // (注1)d[j]=d[k]+a[k][j]可能只是得到了過度值而不是最優解 // 但在下一輪循環里用min找到並標記的k,必然是最優解 // 因為1級循環的遍歷是從初始頂點開始由近及遠的 // 所以每次2級循環之后,至少能確定一個頂點的d值 // 可以畫一個具體的圖來幫助理解 for(j=1;j<=n;j++) if(a[k][j]!=0&&!p[j]&&d[j]>d[k]+a[k][j]) d[j]=d[k]+a[k][j]; } //最終輸出從源節點到其他每個節點的最小距離 for(i=1;i<n;i++) printf("%d->",d[i]); printf("%d\n",d[n]); return 0; }