F l o y d Floyd Floyd | 图论经典最短路 无需前置知识
F l o y d Floyd Floyd 适用于时间复杂度 O ( n 3 ) O(n^3) O(n3) 而不TLE的最短路题目
前置知识(当然存图,输入请自行翻书)
为防止你看不懂数组,变量,vector等变量名
一般规定
dis[]:距离,一般dis[i]是s到i(s意义如下)
graph[][]/g[][]:i,j是否有边或边权
n:点数
m:边数
s:起点
t:终点
vector<>g[]:邻接表存图
vis[]:bool,判断点i是否被查看过(
D
i
j
k
s
t
r
a
Dijkstra
Dijkstra 常用)
三角路
我们可以把点理解为 A,B,C等 ,边理解为直线a,b,c
C => E 是32,但这是真的吗? 其实最短路C => A => D=> E 却只要19!
废话——zky
F
l
o
y
d
Floyd
Floyd 应运而生
规定INF是绝对大数,使INF大于所有边权之和(方便更新状态)
/ | A | B | C | D | E |
---|---|---|---|---|---|
A | 0 | 5 | 3 | 6 | INF |
B | 5 | 0 | 6 | INF | INF |
C | 3 | 6 | 0 | INF | 32 |
D | 6 | INF | INF | 0 | 4 |
E | INF | INF | 32 | 4 | 0 |
我们知道zky至真名言
C => E 是32,但这是真的吗? 其实最短路C => A => D=> E 却只要19!
废话——zky
用计算机语言:
对于任意的点i,j,k(k为i到j的中转站)
if(graph[i][j]>graph[i][k]+graph[j][k])
graph[i][j]=graph[i][k]+graph[j][k]
根据以上分析,我们只需要枚举i,j,k即可
void floyd(){
for(int c=1;c<=n;c++){
for(int j=0;j<=n;j++){
for(int i=1;i<=n;i++){
if(graph[i][j]>graph[i][c]+graph[c][j])
graph[i][j]=graph[i][c]+graph[c][j];
}
}
}
}
所以写了个函数(一定是先枚举中转站c不然报错,具体原因比较玄学)
Code Time(题目参考B3647-模板Floyd)
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
int graph[103][103];
void init(){
memset(graph,INF,sizeof graph);//解释一下memset (1)
for(int i=0;i<=102;i++){
graph[i][i]=0;
}
}
void read(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
if(graph[v][u]<w) continue;//因为本题数据可能有重边
graph[v][u]=w;
graph[u][v]=w;
}
}
void floyd(){
for(int c=1;c<=n;c++){
for(int j=0;j<=n;j++){
for(int i=1;i<=n;i++){
if(graph[i][j]>graph[i][c]+graph[c][j])
graph[i][j]=graph[i][c]+graph[c][j];
}
}
}
}
void output(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<graph[i][j]<<" ";
}
cout<<endl;
}
}
signed main(){
init();
read();
floyd();
output();
return 0;
}
解释:
(1)
m
e
m
s
e
t
(
)
memset()
memset() 是一个定义数组初始值的实用函数
用法:memset(数组名,值,sizeof或指针相加)
例memset(a,0,sizeof a),(a,0,a+100)前提是a有100+空间
建议阅读
Dijkstra | 适合蒟蒻(初学者)的算法解析(前置
F
l
o
y
d
Floyd
Floyd )
毕竟单源下时间复杂度
O
(
(
N
+
M
)
∗
l
o
g
N
)
O((N+M)*logN)
O((N+M)∗logN)