最短路Floyd讲解
我们讲述一个最短路算法—
这个算法的本质就是每次去增加一个新点,去更新所有点的最短路。
为什么正确? 我们考虑如下的证明:
对于路径
每次都是去尝试一个新点,
基于
Luogu P1119
给定一张无向带权图,每个点有个修复日期
我们可以先把询问离线下来,然后每当一个点被修建后,我们针对这个点作为
那么这个题其实就是考验你是否理解基础算法的本质了。
与其类似的还有道题,留为思考:
给定一个无向带权图,点有点权,边有边权,定义
Floyd 求最小环
我们现在来想一个问题:
给定一个无向图,求出包含给定点的最小环 (边数大于
具体而言,我们可以对于与
我们假设与其相连的点为
那么我们现在要求全局的最小环该怎么去做?
我们可以去找到这个环上编号最大的点
我们可以在
for(int k=1;k<=n;++k){
for(int i=1;i<k;++i){
for(int j=1;j<i;++j) ans=min(ans,1ll*e[i][k]+1ll*e[j][k]+1ll*f[i][j]);
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j) f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
}
}
Floyd 在传递闭包的用途
何为传递闭包?
给定一个有向图,每次给定询问
这个可以用
for(int k=1;k<=n;++k)
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
f[i][j]= (f[i][j]||(f[i][k]&&f[k][j]));
例题:
给定一个
定义
对于每个点的
Floyd 与倍增的结合
例题一:
Luogu P1613
给定一个有向图,起点为
我们可以定义
for(int i=1;i<=65;++i){
for(int j=1;j<=n;++j){
for(int k=1;k<=n;++k){
for(int z=1;z<=n;++z){
vis[i][j][k]=vis[i][j][k]|| (vis[i-1][j][z]&&vis[i-1][z][k]);
}
}
}
}
然后如果:
我们就向
广搜处理边权相同的最短路之所以正确,是因为最遍历到的代表的一定是最短路,且到源点最短路越小越先出队。
例题二:
给定一个无向图 ,询问
针对部分分,我们可以在
或者我们也可以进行矩阵快速幂来优化
前一种做法是后一种做法的本质。
例题三: 给定一个有向带权图,然后让你找出点数最小的负环。
由于环的点数等于边数,我们可以将点数最小转化为边数最少。
还是一样,我们可以定义
留一道思考题,与刚才思路十分相似:
给定一个无向带权图,让你求出经过边数最小的边权之和大于等于