• Floyd算法 (弗洛伊德)


    定义

    弗洛伊德最短距离算法(Floyd Shortest Path Algorithm)又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法。

    原理

    我们的目标是寻找从点 i 到点 j 的最短路径。

    从任意节点 i 到任意节点 j 的最短路径不外乎2种可能。

      ①直接从 i 到 j。

      ②从 i 经过若干个节点 k 到 j。

         令 Dis(i,j) 为节点 i 到节点 j 的最短路径的距离。

         对于每一个节点k,我们检查 Dis(i,k) + Dis(k,j) < Dis(i,j) 是否成立,如果成立,则Dis(i,j) = Dis(i,k) + Dis(k,j)。

         所以,当我们遍历完所有节点 k,Dis(i,j)中记录的便是 i 到 j 的最短路径的距离。

         ❗弗洛伊德不能处理负权图。

           若求 1->3 的最短路,此情况则会陷入1->2->3->1->2->3->1->2->3......死循环。

    实现

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int inf=0x3f3f3f3f;
    int n,m,e[maxn][maxn];
    void floyd();
    int main()
    {
      int i,u,v,w;
      fill(e[0],e[0]+maxn*maxn,inf);
      for(i=0;i<maxn;i++) e[i][i]=0;
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)
      {
        scanf("%d%d%d",&u,&v,&w);
        e[u][v]=w;
      }
      floyd();
      system("pause");
      return 0;
    }
    void floyd()
    {
      int i,j,k;
      for(k=1;k<=n;k++)
       for(i=1;i<=n;i++)
         for(j=1;j<=n;j++)      
            if(e[i][j]>e[i][k]+e[k][j])                 
                 e[i][j]=e[i][k]+e[k][j];
    }

    扩展

    记录路径

    代码1

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int inf=0x3f3f3f3f;
    int n,m,e[maxn][maxn],path[maxn][maxn],ans[maxn],top=-1;
    void floyd();
    void print(int x,int y);
    int main()
    {
      int i,u,v,w;
      fill(e[0],e[0]+maxn*maxn,inf);
      for(i=0;i<maxn;i++) e[i][i]=0;
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)
      {
        scanf("%d%d%d",&u,&v,&w);
        e[u][v]=w;
      }
      floyd();
      scanf("%d%d",&u,&v);
      ans[++top]=u;
      print(u,v);
      ans[++top]=v;
      for(i=0;i<=top;i++)
       printf("%d%s",ans[i],i==top?"
    ":"->");
      system("pause");
      return 0;
    }
    void print(int x,int y) 
    {
      if(!path[x][y]) return;
      print(x,path[x][y]);
      ans[++top]=path[x][y];
      print(path[x][y],y);
    }
    void floyd()
    {
      int i,j,k;
      for(k=1;k<=n;k++)
       for(i=1;i<=n;i++)
         for(j=1;j<=n;j++)      
            if(e[i][j]>e[i][k]+e[k][j])     
            {
              e[i][j]=e[i][k]+e[k][j];
              path[i][j]=k;
            }                    
    }

    代码2

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int inf=0x3f3f3f3f;
    int n,m,e[maxn][maxn],path[maxn][maxn];
    void floyd();
    void print(int x,int y);
    int main()
    {
      int i,u,v,w;
      fill(e[0],e[0]+maxn*maxn,inf);
      for(i=0;i<maxn;i++) e[i][i]=0;
      for(i=0;i<maxn;i++)
       for(int j=0;j<maxn;j++)
         path[i][j]=j;
      
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)
      {
        scanf("%d%d%d",&u,&v,&w);
        e[u][v]=w;
      }
      floyd();
      scanf("%d%d",&u,&v);
      print(u,v);
      system("pause");
      return 0;
    }
    void print(int x,int y) 
    {
      if(x==y)
      {
        printf("%d",y);
        return ;
      }
      int k=path[x][y];
      printf("%d-->",x);
      print(k,y);
    }
    void floyd()
    {
      int i,j,k;
      for(k=1;k<=n;k++)
       for(i=1;i<=n;i++)
         for(j=1;j<=n;j++)      
            if(e[i][j]>e[i][k]+e[k][j])     
            {
              e[i][j]=e[i][k]+e[k][j];
              path[i][j]=path[i][k];
            }                    
    }

    找环

    有向图和无向图的环是不同的,有向图中至少2个就可以成环,而无向图中至少需要3个顶点才能成环。

    有向图

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int inf=0x3f3f3f3f;
    int n,m,e[maxn][maxn];
    void floyd();
    int main()
    {
      int i,u,v,w,ans=inf;
      fill(e[0],e[0]+maxn*maxn,inf);
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)
      {
        scanf("%d%d%d",&u,&v,&w);
        e[u][v]=w;
      }
      floyd();
      for(i=1;i<=n;i++) ans=min(ans,e[i][i]);
      printf("%d
    ",ans);
      system("pause");
      return 0;
    }
    void floyd()
    {
      int i,j,k;
      for(k=1;k<=n;k++)
       for(i=1;i<=n;i++)
         for(j=1;j<=n;j++)      
            if(e[i][j]>e[i][k]+e[k][j])                 
                 e[i][j]=e[i][k]+e[k][j];
    }

    无向图

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1005;
    const int inf=999999;
    int n,m,e[maxn][maxn],ve[maxn][maxn];
    void floyd();
    int main()
    {
      int i,u,v,w;
      fill(e[0],e[0]+maxn*maxn,inf);
      fill(ve[0],ve[0]+maxn*maxn,inf);
      for(i=0;i<maxn;i++) e[i][i]=ve[i][i]=0;
      
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++)
      {
        scanf("%d%d%d",&u,&v,&w);
        ve[u][v]=e[u][v]=w;
        ve[v][u]=e[v][u]=w;
      }
      floyd();
      system("pause");
      return 0;
    }
    void floyd()
    {
      int MinCost=inf;
      for(int k=1;k<=n;k++)
      {
        for(int i=1;i<k;i++)  //更新k点之前枚举ij求经过ijk的最小环
          for(int j=i+1;j<k;j++)
            MinCost=min(MinCost,e[i][j]+ve[i][k]+ve[k][j]);
    
        for(int i=1;i<=n;i++)  //更新k点
          for(int j=1;j<=n;j++)
            e[i][j]=min(e[i][j],e[i][k]+e[k][j]);  
      }
      if(MinCost==inf) puts("It's impossible.");
      else printf("%d
    ",MinCost);            
    }
  • 相关阅读:
    PHP编程中一些时间和日期代码调用的实例
    想不显示织梦栏目列表页缩略图就是不显示默认缩略图怎么办
    织梦dede文章增加HTML自定义字段字符被过滤问题
    Dedecms友情链接/uploads/fli<x>nk/不显示正确的图片路径错误
    Dedecms教程:整站调用购物车订单数量简单解决办法
    织梦DedeCMS模板常用的内容统计sql标签代码
    DEDECMS首页loop调用留言本带用户头像的方法
    Python 序列、列表(List)、元组(Tuple)
    Python 字符串常用函数
    Python 运算符
  • 原文地址:https://www.cnblogs.com/VividBinGo/p/11588590.html
Copyright © 2020-2023  润新知