bellman-ford算法

bellman-ford算法是用於解決單源最短路徑的算法,與Dijkstra不同的是,它可解決存在負權邊的的情況。同時,它也可以檢測是否存在存在負權值環。

其基本思路如下:

建立一個距離數組dis[],將源點設爲0,其餘點的距離初始化爲無窮大。

將下列操作循環最多n-1次:

對於每條邊,start->end,

if(dis[end] > dis[start] + weight)

                dis[end] = dis[start] + weight;

(該操作稱爲一次"鬆弛"操作)

循環n-1次或沒有任何一條邊能夠經過鬆弛操作可以縮短距離。

接下來就是bellman-ford算法最精彩的地方。我們再循環一次,對每條邊再進行一次鬆弛操作,如果還能縮短距離,說明該圖中存在負權環,也就不存在最短路徑。


對其理解:

由於距離數組一開始除了源點外,距離都設置爲無窮大,所以第一次循環時,必然是鬆弛與起點相連的邊。

其基本內涵相當於從起點開始,不斷向外擴展。

如果起點到某點i存在一條最短路徑的話,就相當於從源點開始,每次都找到從起點到i點最短路徑上的一條邊,類似與dfs的思想。

由於最短路徑最多有n-1條邊,所以最多循環n-1次。同理,如果循環了n-1次後,仍能縮短距離,說明圖中存在負權環。

以下是有向圖的代碼,無向圖可將邊數乘2當做有向圖做。

注意,如果無向圖中存在一條無向的負邊(源點可達),說明是不存在最短路徑的。

代碼:

#include <iostream>
#define INF 999999999
using namespace std;

class Edge
{
public:
    int s,e;
    int weight;
};
int main()
{
    int n;
    int N,M,W;
    int k;
    cin>>n;
    cin>>N>>M>>W;
    int *dis = new int [N+1];       //距離數組
    Edge *edge = new Edge [2*M+N];  //M條無向邊,W條有向表
    bool flag = true;
    while(n--)
    {
        for(int i=1;i<=N;i++)
            dis[i] = INF;
        dis[1] = 0;                 //初始化距離數組
        flag = true;
        k=0;
        for(int i=0;i<M;i++)//將無向邊轉爲兩條有向邊
        {
            int s,e,weight;
            cin>>s>>e>>weight;
            edge[k].s = s,edge[k].e = e,edge[k++].weight=weight;    //儲存兩條邊
            edge[k].s = e,edge[k].e = s,edge[k++].weight=weight;
        }
        for(int i=0;i<W;i++)//儲存有向邊
        {
            int s,e,weight;
            cin>>s>>e>>weight;
            edge[k].s = s,edge[k].e = e,edge[k++].weight = -weight;
        }

        for(int i=0;i<N-1;i++)
        {
            flag = true;
            for(int j=0;j<2*M+W;j++)
            {
                if(dis[edge[j].e] > dis[edge[j].s] + edge[j].weight)
                {
                    dis[edge[j].e] = dis[edge[j].s] + edge[j].weight;
                    flag = false;
                }
            }
            if(flag)
                break;
        }

        flag = false;
        for(int j=0;j<2*M+W;j++)
        {
            if(dis[edge[j].e] > dis[edge[j].s] + edge[j].weight)
            {
                dis[edge[j].e] = dis[edge[j].s] + edge[j].weight;
                flag = true;
                break;
            }
        }

        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

可以看出 時間複雜度爲V*E 即結點數乘以邊數,時間複雜度較大。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章