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

  

 

posted @ 2019-10-17 18:55  留幸愉  阅读(271)  评论(0编辑  收藏  举报