修改:时间复杂度是假的
前置芝士:Floyd算法
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
这是一个朴素的 Floyd,它的时间复杂度是 O ( N 3 ) O(N^3) O(N3)。
注意到,在第二层循环中,很可能 i i i 和 k k k 之间根本不存在一条边,这是后第三层循环是在白费功夫,因为根本不可能成功转移,这个时候就可以进行一个剪枝。
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
if(dis[i][k]==0x3f3f3f3f)
{
continue;
}
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
这个剪枝一个特点在于,它不是玄学优化,而是真正优化了时间复杂度。设边数为 M M M 条,则直接连通的 ( i , k ) (i,k) (i,k) 的组合必定只有 M M M 个,所以最内层循环最多只会有 M M M 次。
所以,这个剪枝将 Floyd 的时间复杂度优化到了 O ( N M ) O(NM) O(NM)。
这个剪枝的效果取决于图的稠密性,如果图很稠密,那优化了就像优化了一样。但如果图很稀疏,到 N N N 和 M M M 同阶的程度,那就跑的飞快,能过 5 × 10 3 5 \times 10 ^3 5×103 甚至 10 4 10^4 104(很大的一个问题是空间存不下了)的数据。
相比之下,它吊打了 N N N 次 Dijkstra 和 SPFA 的做法(分别是 O ( N M log M ) O(NM \log M) O(NMlogM) 和最劣 O ( N 2 M ) O(N^2M) O(N2M)),但同时代码短的离谱!
这玩意加个判负环应该能跑过Johnson 模板等我有时间试试。
741

被折叠的 条评论
为什么被折叠?



