Bellman-Ford(可解決負權邊)--時間複雜度優化

Bellman-Ford 可解決帶有負權邊的最短路問題數組

  解決負權邊和Dijkstra相比是一個優勢,Bellman-Ford的核心代碼只有4行::測試

u[],v[],w[] 分別存一條邊的頂點、權值,dis[]存從 1 源點到各個頂點的距離
優化

 

for(i=1;i<=n-1;i++)
    for(j=1;j<=m;j++)
        if(dis[v[j]] > dis[u[j]]+w[j])
            dis[v[j]] = dis[u[j]]+w[j];

 

 

  願過程:spa

      循環n-1次,把每一個頂點每條邊都鬆弛;code

     優化方法:blog

      ①,最壞的狀況就是循環了n-1次才求出到每一個頂點的最短路徑,若果在n-1次以前就已經所有鬆弛完成,那麼後面的循環就是多餘io

        優化:class

for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可
{
        flag = 0;
        for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛
        {
            if(dis[v[i]] > dis[u[i]]+w[i])
            {
                dis[v[i]] = dis[u[i]]+w[i];
                flag = 1;
            }
        }
        if(flag == 0) break;//鬆弛也完成,結束
}

 

      ②,原過程:每次循環鬆弛事後,都有已經肯定了的源點到某點最短的路徑,此後這些頂點的最短路的值就會一直保持不變,再也不受後續鬆弛操做的影響,可是每次還要判斷是否須要鬆弛,這裏浪費了時間。循環

     優化:肯定一條邊後總邊數減一,把不能進行本次鬆弛的邊再次後頭存到原數組,鬆弛成功的邊捨棄,再次鬆弛時只對未鬆弛的邊進行操做,m的值會隨着鬆弛預愈來愈小,直到所有完成。方法

for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可
    {
        m = M;//從新賦值後的 m 是數組中存儲邊的條數
        s = 1;flag = 0;
        for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛
        {
            if(dis[v[i]] > dis[u[i]]+w[i])
            {
                dis[v[i]] = dis[u[i]]+w[i];
                M--;    //鬆弛成功,邊數減一
                flag = 1;
            }
            else//把本次不能進行鬆弛的邊從新存儲到當前的數組
            {
                u[s] = u[i];
                v[s] = v[i];
                w[s] = w[i];
                s++;
            }
        }
        if(flag == 0) break;//鬆弛也完成,結束
    }

附完整代碼:

#include <stdio.h>
int main()
{
    int dis[10],i,k,m,n,s=1,u[10],v[10],w[10],M,flag;
    int inf = 99999999;
    scanf("%d%d",&n,&m);
    M = m;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u[i],&v[i],&w[i]);//輸入各邊及權值
    }
    for(i=1;i<=n;i++)
    {
        dis[i] = inf;//初始化爲正無窮
    }
    dis[1] = 0;//以 1 爲源點

    for(k=1;k<=n-1;k++)//共有 n 個頂點,循環n-1次便可
    {
        m = M;//從新賦值後的 m 是數組中存儲邊的條數
        s = 1;flag = 0;
        for(i=1;i<=m;i++)//對當前全部的邊進行鬆弛
        {
            if(dis[v[i]] > dis[u[i]]+w[i])
            {
                dis[v[i]] = dis[u[i]]+w[i];
                M--;    //鬆弛成功,邊數減一
                flag = 1;
            }
            else//把本次不能進行鬆弛的邊從新存儲到當前的數組
            {
                u[s] = u[i];
                v[s] = v[i];
                w[s] = w[i];
                s++;
            }
        }
        if(flag == 0) break;//鬆弛也完成,結束
    }

    for(i=1;i<=n;i++)
    {
        printf("%d ",dis[i]);
    }
    return 0;
}

 

 

 測試數據1:

5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3

 

運行結果:

0 -3 -1 2 4

 

測試數據2:

5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4
4 5 5
5 3 6

 

運行結果:

0 2 5 9 9
相關文章
相關標籤/搜索