Bellman_ford算法


   摘自百度百科    

          Bellman-ford算法是求含負權的單源最短路徑算法,效率很低,但代碼很容易寫。即進行不停地松弛(relaxation),每次松弛把每條邊都更新一下,若n-1次松弛后還能更新,則說明圖中有負環(即負權回路,本文最后有解釋),無法得出結果,否則就成功完成。Bellman-ford算法有一個小優化:每次松弛先設一個旗幟flag,初值為FALSE,若有邊更新則賦值為TRUE,最終如果還是FALSE則直接成功退出。Bellman-ford算法浪費了許多時間做無必要的松弛,所以SPFA算法用隊列進行了優化,效果十分顯著,高效難以想象。SPFA還有SLF,LLL,滾動數組等優化。

      Dijkstra算法中不允許邊的權是負權,如果遇到負權,則可以采用Bellman-Ford算法。

 

  Bellman-Ford算法能在更普遍的情況下(存在負權邊)解決單源點最短路徑問題。對於給定的帶權(有向或無向)圖 G=(V,E),其源點為s,加權函數w是 邊集 E 的映射。對圖G運行Bellman-Ford算法的結果是一個布爾值,表明圖中是否存在着一個從源點s可達的負權回路。若不存在這樣的回路,算法將給出從源點s到 圖G的任意頂點v的最短路徑d[v]。

 

  適用條件&范圍

 

  1.單源最短路徑(從源點s到其它所有頂點v);

 

  2.有向圖&無向圖(無向圖可以看作(u,v),(v,u)同屬於邊集E的有向圖);

 

  3.邊權可正可負(如有負權回路輸出錯誤提示);

 

  4.差分約束系統;

 

  Bellman-Ford算法描述:

 

  1,.初始化:將除源點外的所有頂點的最短距離估計值 d[v] ←+∞, d[s] ←0;

 

  2.迭代求解:反復對邊集E中的每條邊進行松弛操作,使得頂點集V中的每個頂點v的最短距離估計值逐步逼近其最短距離;(運行|v|-1次)

 

  3.檢驗負權回路:判斷邊集E中的每一條邊的兩個端點是否收斂。如果存在未收斂的頂點,則算法返回false,表明問題無解;否則算法返回true,並且從源點可達的頂點v的最短距離保存在 d[v]中。

 

  描述性證明:

 

  首先指出,圖的任意一條最短路徑既不能包含負權回路,也不會包含正權回路,因此它最多包含|v|-1條邊。

 

  其次,從源點s可達的所有頂點如果 存在最短路徑,則這些最短路徑構成一個以s為根的最短路徑樹。Bellman-Ford算法的迭代松弛操作,實際上就是按頂點距離s的層次,逐層生成這棵最短路徑樹的過程。

 

  在對每條邊進行1遍松弛的時候,生成了從s出發,層次至多為1的那些樹枝。也就是說,找到了與s至多有1條邊相聯的那些頂點的最短路徑;對每條邊進行第2遍松弛的時候,生成了第2層次的樹枝,就是說找到了經過2條邊相連的那些頂點的最短路徑……。因為最短路徑最多只包含|v|-1 條邊,所以,只需要循環|v|-1 次。

 

  每實施一次松弛操作,最短路徑樹上就會有一層頂點達到其最短距離,此后這層頂點的最短距離值就會一直保持不變,不再受后續松弛操作的影響。(但是,每次還要判斷松弛,這里浪費了大量的時間,怎么優化?單純的優化是否可行?)

 

  如果沒有負權回路,由於最短路徑樹的高度最多只能是|v|-1,所以最多經過|v|-1遍松弛操作后,所有從s可達的頂點必將求出最短距離。如果 d[v]仍保持 +∞,則表明從s到v不可達。

 

  如果有負權回路,那么第 |v|-1 遍松弛操作仍然會成功,這時,負權回路上的頂點不會收斂。

C++ pseudo code

Bellman-Ford(G,w,s) :boolean //圖G ,邊集 函數 w ,s為源點   
for each vertex v ∈ V(G) do //初始化 1階段   
          d[ v] ←+∞ 
 d[s] ←0; //1階段結束 
 for i=1 to |v|-1 do //2階段開始,雙重循環。
    for each edge(u,v) ∈E(G) do //邊集數組要用到,窮舉每條邊。           If d[v]> d[u]+ w(u,v) then //松弛判斷,w(w,v)是u到v的權值
             d[v]=d[u]+w(u,v) //松弛操作 2階段結束 
 for each edge(u,v) ∈E(G) do
   If d[v]> d[u]+ w(u,v) then
         Exit false   //存在負權回路
 Exit true 

 負權回路

 在一個圖里每條邊都有一個權值(有正有負)
如果存在一個環(從某個點出發又回到自己的路徑),而且這個環上所有權值之和是負數,那這就是一個負權環,也叫負權回路
存在負權回路的圖是不能求兩點間最短路的,因為只要在負權回路上不斷兜圈子,所得的最短路長度可以任意小。(轉自百度知道)

 代碼實現:

  Bellman-ford算法的運行時間為O(VE),V為頂點數,E為邊數。

/*************************************************************************
    > File Name: Bellman_ford.cpp
    > Author: He Xingjie
    > Mail: gxmshxj@163.com
    > Created Time: 2014年06月08日 星期日 22時33分07秒
    > Description: 
 ************************************************************************/
#include<iostream>
#include<cstdio>

using namespace std;

#define INF 99999
int map[100][100], dist[100];

bool Bellman_ford(int n, int s)
{
    int v, u;

    for (v=1; v<n; v++)
    {
        if (map[s][v] == INF)
            dist[v] = INF;
        else
            dist[v] = map[s][v];
    }

    dist[s] = 0;

    for (v=1; v<n; v++)
        for (u=0; u<n; u++)
            if (map[u][v] < INF)  //u->v has path
                if (dist[v] > dist[u] + map[u][v])
                    dist[v] = dist[u] + map[u][v];

    //遍歷所有的邊
    for (v=0; v<n; v++)
        for (u=0; u<n; u++)
            if (v != u && map[u][v] != INF)
                if (dist[v] > dist[u] + map[v][u])
                    return false;

    return true;
}

void PrintMap(int n)
{
    int i, j;
    //輸出矩陣
    for (i=0; i<n; i++)
    {
        for (j=0; j<n; j++)
        {
            if (map[i][j] == INF)
                printf("INF ");
            else
                printf("%d  ", map[i][j]);
        }

        printf("\n");
    }
}

void PrintShortestValue(int n)
{
    int i;

    for (i=1; i<n; i++)
        printf("%d:%d ", i, dist[i]);
    printf("\n");
}

int main()
{
    int n, m, i, j;

    freopen("input.txt", "r", stdin);
    cin>>n>>m;    //n是頂點數,m是邊數

    //初始化
    for (i=0; i<n; i++)
    {
        for (j=0; j<n; j++)
            map[i][j] = INF;
    }

    //輸入
    for(int i=1; i<=m; i++)
    {
        int i,j;
        cin>>i>>j;
        cin>>map[i][j];
    }

    PrintMap(n);

    Bellman_ford(n, 0);
    PrintShortestValue(n);

    return 0;
}

 

 

 


免責聲明!

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



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