说明:CSDN和公众号文章同步发布,需要第一时间收到最新内容,请关注公众号【比特正传】。
在我国两弹一星事业起步初期,钱学森先生就提出:【先仿制,后改进,再设计】,学习算法亦是如此,尤其是模板题,先模仿写,等熟练了可以考虑该算法是否可以继续优化(SPFA算法就是西南交通大学 段凡丁教授基于Bellman-ford做的改进),最后可以设计自己的算法解决某类问题。
之前的图论合集文章中讲了最短路、拓扑排序、最小生成树等算法,文章链接如下:
之前提到的Dijkstra、Bellman-ford和SPFA求最短路,是单源最短路,即求解从某一个点出发到其他点的最短距离,那么多源汇最短路怎么办呢?可以通过Floyd(弗洛伊德)算法进行求解。
1、问题描述
题目链接:
https://www.luogu.com.cn/problem/B3647
本题需求解任意两点间的最短路,使用Floyd算法来完成。
2、算法思想和步骤
初始化dist[i][j]为节点i到结点j的距离,那么dist[i][j]=0,节点到节点自己的距离肯定为0,其次,如果i和j相连,那么初始值为两节点边的权值,dist[i][j]=w,否则均为无穷大INF。
Floyd算法步骤很简单,简单粗暴的三层循环,第一层循环遍历中间节点k,第二层循环遍历起点i,第三层循环遍历终点j,目的是从节点i走到节点j,如果可以通过i走到k,然后从k走到j,且这种方式的权值更小,那么更新dist[i][j] = dist[i][k] + dist[k][j]。
步骤很简单,代码写起来也很简单,Floyd也是模板代码,需要每位同学熟练编写。
3、编写code
#include<bits/stdc++.h>
using namespace std;
const int N = 105, INF = 0x3f3f3f3f;
int n, m, u, v, w, dist[N][N];
void init() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
if(i == j) dist[i][j] = 0; // 到自己的距离为0
else dist[i][j] = INF; // 否则先初始化为"无穷大"
}
}
}
void floyd() { // Floyd算法的模板代码,需要熟练编写
for(int k=1; k<=n; k++) {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); // 更新结点i到节点j的权值
}
}
}
return;
}
void printAns() {
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
cout << dist[i][j] << " ";
}
cout << "\n";
}
}
int main() {
cin >> n >> m;
init();
for(int i=1; i<=m; i++) {
cin >> u >> v >> w;
dist[u][v] = min(w, dist[u][v]);
dist[v][u] = min(w, dist[v][u]);
}
floyd();
printAns(); // 按照题目要求输出结果
return 0;
}