Dijkstra算法思想理解


有向圖 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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM