多源点最短路径 Floyd

由 5+1 发布

如果有一张图,我希望获得从每一个点到其他另外的所有点的距离的之和,那么你该怎么做呢?

下面这个 Floyd 算法就非常适用

Floyd

Floyd 采用了动态规划的思想,来解决一个有向图 $G=(V,E)$ 上每一对顶点间的最短路径问题。它允许权值为负数。

对于任意一对顶点 $i$ 和 $j$ ($i,j \in V$),观察从 $i$ 到 $j$ 且经过中间顶点的最短路径,设 $p$ 为其中的一条最小值路径,Floyd 就是利用了路径 $p$ 与 $i$ 到 $j$ 之间的最短路径之间的联系。这一联系依赖于 $k$ 是否是路径 $p$ 中的中间点。

其实我们就对于每一个点的距离 $d[ij]$ 规定如下:

$$d[ij] = \left\{ \begin{array}{rcl}0&i=j\\w(i,j)&i到j存在边\\INF&i到j不存在边\end{array}\right.$$

在动态规划更新时,每一个点的距离 $d[ij]$ 是

$$d[ij] = \min(d[ij], d[ik] + d[kj])$$

实现

基于上面这个式子,我们在用一个循环来寻找中间点,然后再用两层循环来动态规划 $i,j$ 。然后里面根据第一个公式写出动态方程。

for (int i = 1; i <= n; i ++)
{
  for (int j = 1; j <= n; j ++)
  {
    if (i == j)
      d[i][j] = 0;
    else if (w[i][j])
      d[i][j] = w[i][j];
    else
      d[i][j] = INF;
  }
}

for (int k = 1; k <= n; k ++)
  for (int i = 1; i <= n; i ++)
    for (int j = 1; j <= n; j ++)
      d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

其中 w 是一个邻接矩阵数组。d[i][j] 是表示从 $i$ 到 $j$ 的最短距离。

时间复杂度

考虑使用任何一个算法都需要计算它的时间复杂度,否则超时你都不知道咋回事。

执行一次三重循环内部的动态转移方程的时间复杂度是 $O(1)$ ,三重循环是从 $1$ 到 $n$ 的,所以整个的时间复杂度就是 $O(n^3)$ 。所以如果题目的 $n$ 特别大,我们还是选用做好多次 Dijkstra 吧。


暂无评论

发表评论