1. 程式人生 > >Codeup 問題 B: 演算法7-16:弗洛伊德最短路徑演算法

Codeup 問題 B: 演算法7-16:弗洛伊德最短路徑演算法

題目描述

在帶權有向圖G中,求G中的任意一對頂點間的最短路徑問題,也是十分常見的一種問題。

解決這個問題的一個方法是執行n次迪傑斯特拉演算法,這樣就可以求出每一對頂點間的最短路徑,執行的時間複雜度為O(n3)。

而另一種演算法是由弗洛伊德提出的,時間複雜度同樣是O(n3),但演算法的形式簡單很多。

可以將弗洛伊德演算法描述如下:

在本題中,讀入一個有向圖的帶權鄰接矩陣(即陣列表示),建立有向圖並按照以上描述中的演算法求出每一對頂點間的最短路徑長度。

 

輸入

輸入的第一行包含1個正整數n,表示圖中共有n個頂點。其中n不超過50。

以後的n行中每行有n個用空格隔開的整數。對於第i行的第j個整數,如果大於0,則表示第i個頂點有指向第j個頂點的有向邊,且權值為對應的整數值;如果這個整數為0,則表示沒有i指向j的有向邊。當i和j相等的時候,保證對應的整數為0。

輸出

共有n行,每行有n個整數,表示源點至每一個頂點的最短路徑長度。如果不存在從源點至相應頂點的路徑,輸出-1。對於某個頂點到其本身的最短路徑長度,輸出0。

請在每個整數後輸出一個空格,並請注意行尾輸出換行。

樣例輸入

<span style="color:#333333">4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
</span>

樣例輸出

<span style="color:#333333">0 3 2 1 
6 0 4 7 
2 5 0 3 
3 6 1 0 
</span>

提示

 

在本題中,需要按照題目描述中的演算法完成弗洛伊德演算法,並在計算最短路徑的過程中將每個頂點是否可達記錄下來,直到求出每一對頂點的最短路徑之後,演算法才能夠結束。

 

相對於迪傑斯特拉演算法,弗洛伊德演算法的形式更為簡單。通過一個三重迴圈,弗洛伊德演算法可以方便的求出每一對頂點間的最短距離。

 

另外需要注意的是,為了更方便的表示頂點間的不可達狀態,可以使用一個十分大的值作為標記。而在題目描述中的演算法示例使用了另外一個三維陣列對其進行表示,這使原本的O(n3)時間複雜度增長到了O(n4),這也是需要自行修改的部分。

 

 

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

int n,m,T;
const int INF = 0x3fffffff;
const int MAXV = 100;

int dis[MAXV][MAXV];
void Floyd()
{
	for (int k=0;k<n;k++)
	{
		for (int i=0;i<n;i++)
		{
			for (int j=0;j<n;j++)
			{
				if (dis[i][k] != INF && dis[k][j]!=INF&&dis[i][k] +dis[k][j]<dis[i][j])
				{
					dis[i][j] = dis[i][k]  + dis[k][j];
				}
			}
		}
	}	
}

int main()
{
	int u,v,w;
	fill(dis[0],dis[0]+MAXV*MAXV , INF);
	cin>>n;
	for (int i=0;i<n;i++)
	{
		for (int j=0;j<n;j++)
		{
			cin>>dis[i][j];
			if (dis[i][j]==0 && i!=j)
			dis[i][j] = INF;
		}
	}	
	Floyd();
	
	for (int i=0;i<n;i++)
	{
		for (int j=0;j<n;j++)
		{
			if (dis[i][j]==INF)
			cout<<"-1"<<" ";
			else
			cout<<dis[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}