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];

 

 

  願過程:

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

     優化方法:

      ①,最壞的情況就是循環了n-1次才求出到每個頂點的最短路徑,若果在n-1次之前就已經全部松弛完成,那么后面的循環就是多余

        優化:

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

 

 

 

 


免責聲明!

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



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