Floyd的一个奇怪剪枝优化

修改:时间复杂度是假的

前置芝士: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 模板等我有时间试试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值