弗洛伊德算法是求任意点到所有点的最短距离
任意节点i到j的最短路径两种可能:
- 直接从i到j;
- 从i经过若干个节点k到j。
假如现在只允许经过1号顶点,求任意两点之间的最短路程,应该如何求呢?只需判断e[i][1]+e[1][j]是否比e[i][j]要小即可。e[i][j]表示的是从i号顶点到j号顶点之间的路程。e[i][1]+e[1][j]表示的是从i号顶点先到1号顶点,再从1号顶点到j号顶点的路程之和。其中i是1~n循环,j也是1~n循环,代码实现如下。
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if (e[i][j] > e[i][1] + e[1][j])
e[i][j] = e[i][1] + e[1][j];
}
}
在只允许经过1号顶点的情况下,更新了任意两点之间的最短路程,那么依次允许经过所有顶点的情况下更新任意两点之间的最短路程,最终求得的最短路程既是任意两点之间最终的最短路程。代码实现如下。
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j])
e[i][j]=e[i][k]+e[k][j];
算法分析
适用范围:Floyd-Warshall算法不能解决带有“负权回路”(或者叫“负权环”)的图,因为带有“负权回路”的图没有最短路。无负权回路即可,边权可正可负,运行一次算法即可求得任意两点间最短路。
优缺点:
Floyd算法适用于APSP(AllPairsShortestPaths),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于Dijkstra算法。
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单
缺点:时间复杂度比较高,不适合计算大量数据。
时间复杂度:O(n^3);空间复杂度:O(n^2);
附上练习题
P2935 [USACO09JAN]Best Spot S
链接:https://www.luogu.org/problemnew/show/P2935
AC代码
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
int s[505][505]= {0};
int c[505];
int main() {
int n,f,m,u,v,w,summ=1e9,a;
cin >> n >> f >> m;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
if(i!=j)
s[i][j]=1e9;
}
for(int i=1; i<=f; i++)
cin >> c[i];
for(int i=1; i<=m; i++) {
scanf("%d%d%d",&u,&v,&w);
s[u][v]=w;
s[v][u]=w;
}
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
s[i][j]=min(s[i][j],s[i][k]+s[k][j]);
s[j][i]=s[i][j];
}
for(int k=1; k<=n; k++){
int sum=0;
for(int i=1; i<=f; i++)
sum+=s[k][c[i]];
if(sum<summ){
summ=sum;
a=k;
}
}
cout << a;
return 0;
}