如果保证有对称的邻接矩阵,是否存在降低Floyd-Warshall运行时常数因子的优化?
答案 0 :(得分:11)
经过一番思考后我想出了:
for (int k = 0; k < N; ++k)
for (int i = 0; i < N; ++i)
for (int j = 0; j <= i; ++j)
dist[j][i] = dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
现在我们当然都需要证明它是正确和快速的。
正确性更难以证明,因为它依赖于Floyd-Warshall的证明,这是非平凡的。这里给出了一个很好的证据:Floyd-Warshall proof
输入矩阵为symmetric。现在证明的其余部分使用修改后的Floyd-Warshall证明,表明2个内环中的计算顺序无关紧要,图 保持 对称每一步之后。如果我们显示这两个条件都是真的那么两个算法都做同样的事情。
我们将dist[i][j][k]
定义为i
到j
的距离,使用集合{0, ..., k}
中的顶点作为从i
到j
的路径上的中间顶点dist[i][j][k-1]
。
i
定义为从j
到dist[i][j][k] = min(dist[i][j][k-1], dist[i][k][k-1] + dist[k][j][k-1])
的边的权重。如果之间没有边缘,则该重量被视为无穷大。
现在使用与上面链接的证据中使用的逻辑相同的逻辑:
dist[i][k][k]
现在计算dist[k][i][k]
(同样适用于dist[i][k][k] = min(dist[i][k][k-1], dist[i][k][k-1] + dist[k][k][k-1])
):
dist[k][k][k-1]
现在,由于dist[i][k][k] = dist[i][k][k-1]
不能为负数(或者我们在图表中有negative loop),这意味着dist[k][k][k-1] = 0
。因为如果min()
,则两个参数都相同,否则选择dist[i][k][k] = dist[i][k][k-1]
的第一个参数。
现在,因为dist[i][j][k]
,在计算dist[i][k]
时,dist[k][j]
或k
在其路径中是否允许dist[i][j][k-1]
并不重要。由于dist[i][j][k]
仅用于计算dist[i][j]
,因此dist[i][j][k-1]
将在矩阵中保留dist[i][j][k]
,直到计算出i
为止。如果j
或k
等于dist[i][j] = dist[j][i]
,则适用上述情况。
因此,计算的顺序并不重要。
现在我们需要在算法的所有步骤之后显示dist[a][b] = dist[b][a]
。
对于所有a
和b
,我们从对称网格dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
= min(dist[j][i], dist[k][i] + dist[j][k])
= min(dist[j][i], dist[j][k] + dist[k][i])
= dist[j][i]
开始。
dist[a][b] = dist[b][a]
因此我们的任务都是正确的,它将保持dist[i][j] = dist[j][i]
的不变量。因此,在算法的所有步骤之后min()
因此,两种算法都会产生相同,正确的结果。
速度更容易证明。内循环的调用次数刚刚超过通常调用的次数的一半,因此函数的速度大约是其两倍。只是稍微慢了,因为你仍然分配了相同的次数,但这并不重要,因为for (int k = 0; k < N; ++k) {
for (int i = 0; i < k; ++i)
for (int j = 0; j <= i; ++j)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[j][k]);
for (int i = k; i < N; ++i) {
for (int j = 0; j < k; ++j)
dist[i][j] = min(dist[i][j], dist[k][i] + dist[j][k]);
for (int j = k; j <= i; ++j)
dist[i][j] = min(dist[i][j], dist[k][i] + dist[k][j]);
}
}
占用了大部分时间。
如果您发现我的证明有任何问题,无论技术如何,请随时指出,我会尝试解决。
修改强>
您可以通过更改循环来加速并节省一半的内存:
{{1}}
这只是分解了上面针对优化算法的循环,所以它仍然是正确的,它可能会获得相同的速度,但占用的内存只有一半。
感谢Chris Elion的想法。
答案 1 :(得分:2)
(使用维基百科文章中的伪代码中的符号)我相信(但尚未测试)如果edgeCost矩阵是对称的,那么路径矩阵在每次迭代后也将是对称的。因此,您只需要在每次迭代时更新一半的条目。
在较低级别,您只需要存储矩阵的一半(因为d(i,j)= d(j,i)),因此您可以减少使用的内存量,并希望减少数量缓存未命中,因为您将多次访问相同的数据。