【算法】最短路

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])即可。此时就是在求有向图的传递闭包了。

原文地址:https://www.cnblogs.com/streamazure/p/12919388.html