【算法-图论基础】最短路径-弗洛伊德算法

03-01 1026阅读

【算法-图论基础】最短路径-弗洛伊德算法

在生活中,我们往往会遇到这样的问题,从地点A到地点B,选择什么线路,选用哪几种交通工具的组合,花费的时间最少?

这个问题中,我们可以借助欧拉使用的数学工具——图论来研究,我们将每一个地点抽象为点,道路或者一个阶段的过程抽象为边,花费的时间就是边的权值。这样,问题就简化为在一个图中找两点之间的最短路径。

怎样解决这个问题呢,罗伯特·弗洛伊德给出了答案。

弗洛伊德算法采用动态规划的思想,假设我们要找的最短路径在点A与点B之间,那么,图中的所有点只有两种情况,要么在这条最短路径上(也就是中间点),要么不在这条最短路径上,我们可以根据这个来得出状态转移方程,依次将图中的每个点作为中间点遍历即可。

下面的题目来自蓝桥题库:

【算法-图论基础】最短路径-弗洛伊德算法

输入输出样例

输入:

3 3 3
1 2 1
1 3 5
2 3 2
1 2
1 3
2 3

输出:

1
3
2

按照题目意思我们可以得到下图:

【算法-图论基础】最短路径-弗洛伊德算法

此时,我们只考虑边权值为正。

在弗洛伊德算法中,我们采用邻接矩阵存图,因为这是天然的dp数组(两点之间无连接则值记为无穷大,方便找最小值),同时,为了能够得到最短路径我们用 f [ x ] [ y ] f[x][y] f[x][y]来记录从x到y的最短路径(保存y的前一个点)。

【算法-图论基础】最短路径-弗洛伊德算法

我们考虑图中的每一个点。

1、当点1作为中间点时(A->…->1->…->B)

更新两个数组, d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i ] [ 1 ] + d p [ 1 ] [ j ] ) dp[i][j] = min(dp[i][j], dp[i][1] + dp[1][j]) dp[i][j]=min(dp[i][j],dp[i][1]+dp[1][j]) ,如果 d p [ i ] [ j ] = d p [ i ] [ 1 ] + d p [ 1 ] [ j ] dp[i][j]=dp[i][1]+dp[1][j] dp[i][j]=dp[i][1]+dp[1][j],对应 f [ i ] [ j ] = f [ 1 ] [ j ] f[i][j]=f[1][j] f[i][j]=f[1][j](注意只能取后半段)。

在本题的环境下,很显然,绿色部分是不用更新的,保留即可。

【算法-图论基础】最短路径-弗洛伊德算法

本轮不必更新,保留。

2、当点2作为中间点时(A->…->2->…->B)

【算法-图论基础】最短路径-弗洛伊德算法

黄色部分需要更新。

3、当点3作为中间点时(A->…->3->…->B)

【算法-图论基础】最短路径-弗洛伊德算法

本轮不必更新,保留。

遍历结束,得到最终结果。

【算法-图论基础】最短路径-弗洛伊德算法

再用查表的方法就能得到两点之间的最短路径值。

那么如何得到两点间的最短路径呢?

;利用f数组,我们知道A到B的最短路径中,B的前驱点是 f [ A ] [ B ] f[A][B] f[A][B],即 A − > . . . − > f [ A ] [ B ] − > B A->...->f[A][B]->B A−>...−>f[A][B]−>B,我们再将 f [ A ] [ B ] f[A][B] f[A][B]看作是 B B B,一直向前倒推即可。

AC代码放在下面:

#include
using namespace std;
#define int long long
const int N = 1e3 + 10;
const int INF = 0x3f3f3f3f3f3f3f3f;
int n, m, q;
int a[N][N];
void init() {
	for (int i = 1; i 
		for (int j = 1; j 
			if (i != j) a[i][j] = INF;
		}
	}
	return;
}
void floyd() {
	for (int i = 1; i 
		for (int j = 1; j 
			if (j == i) continue;
			for (int k = 1; k 
				if (k == j || k == i) continue; // 跳过对角线
				if (a[j][k]  a[j][i] + a[i][k]) {
					a[j][k] = a[j][i] + a[i][k];
				} // 更新最短路径长度及最短路径
			}
		}
	}
	return;
}
signed main() {
	cin  n  m >> q;
	init();
	for (int i = 1; i 
		int from, to, value;
		cin > from >> to >> value;
		a[from][to] = a[to][from] = min(a[from][to],value);
	} // 邻接矩阵存图
	floyd();
	while (q--) {
		int f, t;
		cin >> f >> t;
		if(a[f][t] 
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]