Bellman-Ford------解決負權邊

這幾天一直在搞最短路專題,快開學了,希望能搞定這塊和並查集,開學就弄數據結構和數學了。

其實Bellman-Ford算法是在於解決Dijkstra算法算不能解決的帶有負權邊的情況下產生的,其實Bellman-Ford算法相當的簡單,核心代碼只有4行的樣子,但是真正理解這4行代碼其實也是不難的。。。。

for ( int k = 1;k <= n-1;k++ )
{
	for ( int i = 1;i <= m;i++ )
	{
		if( dis[v[i]] > dis[u[i]]+w[i] )
		{
			dis[v[i]] = dis[u[i]]+w[i];
		}
	}
}
這簡單的四行代碼分別是什麼意思呢,其實不難,先看第一個循環吧,說的就是k: 1->n-1,總共進行了n-1次的循環,第二層循環是對於每一條邊,分別枚舉各個情況下的鬆弛操作,說白了,就是對於這個圖中的所有邊進行最多n-1次鬆弛操作。

u[i] , v[i] , w[i] 分別表示什麼呢?表示的是以u[i]爲起點,v[i]爲終點的,權值爲w[i]的一條邊了。

當然認真想想這個鬆弛操作也是不難的。。。我們只需要知道u[i]是起點,v[i]是終點,然後從源點到達終點的邊可以和另外兩條邊構成一個三角形,這樣的話,我們就可以得到了這個鬆弛的關係了。。。好了,其實Bellman-Ford算法就是這麼簡單,關於這個算法的應用,其實,他不僅僅是用來求最短路徑的,還可以判斷一個圖中是否存在負權迴路,要想知道一個圖中是不是存在負權的迴路,我們知道,在對於每一條邊進行鬆弛操作的過程中,dis[ ]這個數組的值會在第k次鬆弛的操作後而保持不變( 1<=k<=n-1),關於他的上限爲什麼會是n-1的證明,我們會在後面繼續講到。如果在進行完n-1次操作後,dis[ ]的數組中的元素的值還是依舊在發生變化,那麼我們就可以認爲這個圖中存在了負權的迴路了,因爲你想啊,如果有一個圖中有負權的迴路,那麼這個圖就不可能存在最短路,因爲我每次都都在個圈,走上1000,,000次,值會原來越小。

關於他的上限爲n-1次,其實也不難理解,如果一個圖中有n個頂點的話,那麼如果不存在迴路,至多只能有n-1條邊,有了這個概念,我們剛剛已經分析了,要想存在最短路,是不能有負權迴路的,這個時候,我們來分析下,又不有可能存在一個正權迴路,答案當然也是不可能的,因爲如果存在正權迴路的話,最短路一定不會包括它,因爲如果走進了這個圈,權值會越加越大。。。。

好了,這些就是關於Bellman-Ford算法的一些簡單的介紹,,有了這些介紹,我們在學習SPFA的過程中就會打下良好的基礎了,,,


代碼:

# include<cstdio>
# include<iostream>

using namespace std;

# define inf 99999999

int u[10];
int v[10];
int w[10];
int dis[10];
int n,m;

void input()
{
    for ( int i = 1;i <= m;i++ )
    {
        cin>>u[i]>>v[i]>>w[i];
    }
}

void init()
{
    for ( int i = 1;i <= n;i++ )
    {
        dis[i] = inf;
    }
    dis[1] = 0;
}

void solve()
{
    int check;
    for ( int k = 1;k <= n-1;k++ )
    {
        for ( int i = 1;i <= m;i++ )
        {
            check = 0;
            if ( dis[v[i]] > dis[u[i]] + w[i] )
            {
                dis[v[i]] = dis[u[i]] + w[i];
                check = 1;
            }

        }
        if ( check == 0 )
            break;
    }

}

void output()
{
    int flag = 0;
    for ( int i = 1;i <= m;i++ )
    {
        if ( dis[v[i]] > dis[u[i]]+w[i] )
        {
            flag = 1;
        }
    }
    if ( flag == 1 )
    {
        cout<<"此圖含有負權迴路"<<endl;
    }
    else
    {
        for ( int i = 1;i <= n;i++ )
        {
            cout<<dis[i]<<" ";
        }
    }
}


int main(void)
{
    while ( cin>>n>>m )
    {
        input();
        init();
        solve();
        output();
    }


    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章