Floyd 算法是一种用于寻找加权图中所有顶点对之间最短路径的经典算法,它能够处理负权边,但不能处理负权环。即如果边权有负数,切负权边与其他边构成了环就不能用该算法。该算法的时间复杂度为 \(O(V^3)\),其中 V 是图中顶点的数量。
算法核心思想
Floyd 算法的核心思想是动态规划。它通过逐步引入中间顶点来不断更新任意两点之间的最短路径。具体来说:
- 初始化 :假设图用邻接矩阵
dist[][]
表示,其中dist[i][j]
表示顶点i
到顶点j
的初始距离。如果i
和j
之间没有直接边,则dist[i][j]
为无穷大(通常用一个很大的数表示)。 - 动态规划更新 :对于每一个中间顶点
k
,检查是否可以通过k
作为中间点来缩短从i
到j
的路径。即更新条件为: \(\text{dist}[i][j] = \min(\text{dist}[i][j], \text{dist}[i][k] + \text{dist}[k][j])\) - 重复步骤 2 :依次考虑所有中间顶点
k
从0
到V-1
,最终得到所有顶点对之间的最短路径。
例题
题目描述:所有城市间的最短路径
有 n
个城市和 m
条道路,每条道路连接两个城市并具有一定的长度。请计算任意两个城市之间的最短路径长度。如果两个城市之间无法到达,则输出 -1
。
输入格式:
- 第一行包含两个整数
n
和m
(1 ≤ n ≤ 200,0 ≤ m ≤ n(n-1)/2)。 - 接下来的
m
行,每行包含三个整数u
,v
,w
,表示城市u
到城市v
有一条长度为w
的双向道路(1 ≤ u, v ≤ n,1 ≤ w ≤ 1000)。
输出格式:
- 输出一个
n × n
的矩阵,其中第i
行第j
列的元素表示城市i
到城市j
的最短路径长度。如果无法到达,输出-1
。
样例:
输入
4 4
1 2 1
2 3 2
3 4 3
1 4 10
输出
0 1 3 6
1 0 2 5
3 2 0 3
6 5 3 0
答案
#include <iostream>
#include<cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,m;
int graph[205][205];
int main() {
cin>>n>>m;
//距离初始化为最大值
memset(graph,INF,sizeof(graph));
//自己到自己的距离为0
for (int i = 1; i <= n; i++) {
graph[i][i] = 0;
}
int u,v,w;
for(int i=0;i<m;i++){
cin>>u>>v>>w;
graph[u][v]=min(graph[u][v],w);
graph[v][u]=min(graph[v][u],w);
}
//floyed算法
for(int k=1;k<=n;k++){ //中枢点
for(int i=1;i<=n;i++){ //起点
for(int j=1;j<=n;j++){ //终点
if(graph[i][k]+graph[k][j]<graph[i][j]){
graph[i][j]=graph[i][k]+graph[k][j];
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(graph[i][j]==INF){
cout<<-1<<" ";
}
else{
cout<<graph[i][j]<<" ";
}
}
cout<<endl;
}
return 0;
}
应用场景
- 计算图中所有顶点对之间的最短路径。
- 检测图中是否存在负权环。
- 计算传递闭包(Transitive Closure)。