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