【算法】最短路 - Floyd算法

Floyd算法

计算含负权的图上的多源最短路,原理是动态规划。

\(D_{i,j,k}\)为从\(i\)\(j\)的只以\((1...k)\)集合中的结点为中间结点的最短路的长度。

1.若最短路经过点\(k\),则\(D_{i,j,k}=D_{i,k,k-1}+D_{k,j,k-1}\)

2.若最短路不经过点\(k\),则\(D_{i,j,k}=D_{i,j,k-1}\)

因此,\(D_{i,j,k}=min(D_{i,j,k-1},D_{i,k,k-1}+D_{k,j,k-1})\)

(以上摘自 Floyd-Warshall算法 - 维基百科

也就是说,对于任意两个需要求最短路的结点\(i,j\),我们初始化\(D[i][j]\)为结点\(i\)直接连接到结点\(j\)的边的长度(如果不存在这条边,则初始化为\(INF\)。注意,\(INF\)取得过大可能导致在加法计算中溢出,建议将\(INF\)取为"只比最大边权的\(m\)倍(\(m\)为图的总边数)大一点点"的值)。

当然为了省事,除了\(D[i][i]\)以外,全部初始化为\(INF\)也行。

然后遍历\(i,j\)之间的中间结点\(k\),在“经过\(k\)”与"不经过\(k\)“两种状态之间取路径更短的。状态的转移由动态规划完成。

	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			D[i][j] = (i == j ? 0 : INF);
		}
	}
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				D[i][j] = min(D[i][j], D[i][k] + D[k][j]);

当我们不关心任意两点间的长度,而只关心两点间是否存在通路时,只需要将预处理部分做些改动,用1和0表示“连通”与“不连通”,将上述代码中D[i][j] = min(D[i][j], D[i][k] + D[k][j])改为D[i][j]=D[i][j]||(D[i][k]&&D[k][j])即可。此时就是在求有向图的传递闭包了。

猜你喜欢

转载自www.cnblogs.com/streamazure/p/12919388.html