Floyed-Warshall【弗洛伊德算法】
Floyed-Warshall:适用于规模小的图,如果存在负权,需要判断负圈。
权值:类似于从节点 s 到 j 依次经过的长度之和。
类似动态规划:从 s 到 t 的过程程中我们考虑是走还是不走,然后取两者的最小权,最终 s 到 t 的
最小权值之和就是我们要求的最短路径。
做出如下类比:每个点看成一个灯,初始时每个灯都是熄灭状态,结点之间的权值初始化成无穷大。
然后依次计算出两个连通结点之间的距离,灯依次亮起,直到所有的灯光亮起,计算结束。
判断负圈:graph[ i ][ i ]是 i 到外面绕一圈回来的最小路径,if( graph[ i ][ i ] < 0 ) graph[ i ][ i ] = 0;
好处:避免陷入负圈中走不出来。
Floyed 采用三重循环, 复杂度 O(n³)
for(k=1;k<=n;k++) { for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if((i!=j)&&(i!=k)&&(j!=k)&&(f[i][k]+f[k][j]<f[i][j]))//松弛操作,使得f[i][j]是最短的 { f[i][j]=f[i][k]+f[k][j]; } } } }
题意:有 n 家店,每家店坐标是 x,y; 有 m 个连通条件, 问从 s 到 t 的最短路径是多少?
#include <bits/stdc++.h> using namespace std; const int maxn = 1e2 + 7; int a[maxn][3]; double dis_map[maxn][maxn]; //邻接矩阵存图 int n,m,x,y,s,t; // s:起点 , t:终点 , n: 店数 , m: (m+1)家店数连通 , x 与 y 有通道 int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin>>n; for(int i = 1; i <= n; i++) //输入 n 家店的坐标 cin>>a[i][1]>>a[i][2]; cin>>m; memset(dis_map,0x7f,sizeof(dis_map));//将这个矩阵初始化一下 for(int i = 1; i <= m; i++) { cin>>x>>y; double dis = sqrt(pow(double(a[x][1]-a[y][1]),2)+pow(double(a[x][2]-a[y][2]),2)); //有通道的两家店的距离 dis_map[y][x] = dis_map[x][y] = dis; //权值 } cin>>s>>t; for(int k = 1; k <= n; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if((i!=j) && (i!=k) && (j!=k) && (dis_map[i][k]+dis_map[k][j] < dis_map[i][j])) //松弛,使 dis_map[i][j]最小 { dis_map[i][j] = dis_map[i][k] + dis_map[k][j]; } } } } printf("%.2lf",dis_map[s][t]); }
https://www.luogu.org/problem/P1744
永远年轻 永远热泪盈眶!