【算法介绍】
Floyd 用于求每对点之间的距离,可以单向可以双向,可以正权可以负权,但不能有负环
时间复杂度 本质上可以理解成为一种动态规划算法
【模板】
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if((dis[i][k]!=inf) && (dis[k][j]!=inf) && (dis[i][k]+dis[k][j]<dis[i][j]))
dis[i][j]=dis[i][k]+dis[k][j];
【题型】
1.floyd 求解最小环
[例题1] Sightseeing Trip poj1734
[题意] 无向图求至少含三个点的最小环
[分析] 利用floyd的性质,当外层k循环刚开始的时候,保存着不超过k-1的i到j的最短路,然后我们就可以利用dis[i][j]+e[j][k]+e[k][i]来表示一个环,且这个环经过k,由不超过k的节点组成,这样处理即可,最后加上路径处理
[代码]
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int maxn=105;
int e[maxn][maxn],dis[maxn][maxn],pos[maxn][maxn];
vector <int> path;
#define pb push_back
void write(int x,int y)
{
if(!pos[x][y]) return;
write(x,pos[x][y]);
path.pb(pos[x][y]);
write(pos[x][y],y);
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
memset(e,0x3f,sizeof(e));
for(int i=1;i<=m;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e[x][y]=e[y][x]=min(z,e[x][y]); //这种写法处理重边!!
}
memcpy(dis,e,sizeof(e));
int ans=0x3f3f3f3f;
for(int k=1;k<=n;k++)
{
for(int i=1;i<k;i++)
for(int j=i+1;j<k;j++)
{
if((long long)dis[i][j]+e[j][k]+e[i][k]<ans) //这个左侧的long long不开会WA两个点
{
ans=dis[i][j]+e[j][k]+e[i][k];
path.clear(); path.pb(i);
write(i,j);
path.pb(j); path.pb(k);
}
}
//正常的floyd 记录一下转移点
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
pos[i][j]=k;
}
}
if(ans==0x3f3f3f3f)
printf("No solution.");
else
{
for(int i=0;i<path.size();i++)
printf("%d ",path[i]);
}
return 0;
}
【拓展】有向图的最小环,可以从1-n做n次dijkstra,然后每次枚举完u的出边,把dis[u]->inf,然后继续处理后面的部分,当第二次更新到dis[u]时出现环,dis[u]就是环
的长度,目前还未找到合适的例题,待补
2.倍增floyd
利用矩阵乘法的思想,a[i][j]记录i到j经过若干条边的最短路,然后就是Floyd的思想,再加上快速幂即可
[补1] P1613 跑路
[题意] 有向图,1s可以走正好条边(利用跑路器),或者1s正常走一条边,问1-n 的最短时间
[分析] 这道题很明显在暗示我们考虑倍增了,我们先处理出i->j是否存在正好条边的道路,然后利用floyd即可
[代码]
传递闭包 利用0/1记录两者的关系,用floyd传递信息
本文详细介绍了Floyd-Warshall算法用于解决图中两点间最短路径的问题,强调了其在处理负权重时的限制。通过实例解析了如何利用Floyd算法寻找无向图中至少含三个点的最小环,并提供了相应的C++代码实现。同时,文章还探讨了Floyd算法的拓展应用,包括倍增Floyd和传递闭包的概念,并以P1613跑路问题为例展示了倍增Floyd在有向图问题中的应用。
1377

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



