題目描述
在帶權有向圖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。
請在每個整數後輸出一個空格,並請注意行尾輸出換行。
樣例:
輸入:
4
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
輸出:
0 3 2 1
6 0 4 7
2 5 0 3
3 6 1 0
解題思路:
直接使用Floyd算法求解即可。
思想如下:
1、遍歷所有結點
2、每次以當前遍歷的結點 k 作爲中介點,查找是否存在最短路徑
即下面的代碼:
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];
}
3、遍歷結束後,dis中就存放的是任意兩點之間的最短路徑
下面爲AC代碼:
/*
* @Description: Floyd算法
* @Author: sikaozhifu
* @Date: 2020-04-25 14:21:40
* @LastEditTime: 2020-04-25 15:15:53
* @LastEditors: sikaozhifu
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int floyd_max_num = 200;
const int INF = 1000000000;
int dis[floyd_max_num][floyd_max_num];
/**
* @description: Floyd算法
* @param : 鄰接矩陣的結點數
* @return: void
*/
void floyd(int n)
{
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 n; //表示共有 n 個結點
cin >> n;
//初始化距離矩陣
fill(dis[0], dis[0] + floyd_max_num * floyd_max_num, INF);
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(n);
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;
}
system("pause");
return 0;
}