zoukankan      html  css  js  c++  java
  • FLOYD 求最小环


    首先 先介绍一下 FLOYD算法的基本思想

     

    设d[i,j,k]是
    在只允许经过结点1…k的情况下
    i到j的最短路长度
    则它有两种情况(想一想,为什么):
    最短路经过点k,d[i,j,k]=d[i,k,k-1]+d[k,j,k-1]
    最短路不经过点k,d[i,j,k]=d[i,j,k-1]
    综合起来: d[i,j,k]=min{d[i,k,k-1]+d[k,j,k-1],d[i,j,k-1]}
    边界条件: d[i,j,0]=w(i,j)(不存在的边权为∞

    floyd算法的流程:
    把k放外层循环,可以节省内存
    对于每个k,计算每两点的目前最短路
    代码(需记忆)
    for k:=1 to n do
    for i:=1 to n do
      for j:=1 to n do
        if (d[i,k]<∞)and(d[k,j]<∞)
           and(d[i,k]+d[k,j]<d[i,j]) then
              d[i,j]:=d[i,k]+d[k,j]               (以上2段引自刘汝佳的课件)
    时间复杂度:O(n^3)
    FLOYD算法的复杂度虽然是O(n^3)但是它计算出任意一对点之间的最短路。
    FLOYD的代码具有一种简洁美,当时间不允许写其他算法时的时候,写一个FLOYD,骗一部分的分,也是一个不错的选择。
    另一方面,它不怕负权边,也可以判断负权回路。

    接下来通过几个例题让我们看看FLOYD 算法的神奇威力。
    第一. 求最小环
    有向图的最小环和无向图的最小环完全是两种不一样的问题。
    其一般解法都是枚举一条边uv删除,然后求一条uv间的最短路径(假设长S)然后用S+边uv的长,来更新答案。
    如果用SPFA来求最短路,那么复杂度是O(m*km) k的取值取决于 图本身。
    但是FLOYD算法可以在O(n^3)内很轻松地解决这个问题。
    首先对于有向图
     由于一条边UV只能从U到V,而不能逆行之,那么我们只需要更新出图中任意2个点之间的最短路径。
    记F[U,V]表示U到V的最短距离
    G[U,V] 是原图中U到V的边的长
    对于每对(U,V)我们只要将G[U,V]+F[V,U]来更新答案就行了。
    无向图的最小环相对麻烦一些。
    因为我们要避免一条无向边被2次走过(被当做2条边)的情况。
    FOR EXAMPLE
    u v之间有且只有一条边e   我们大可以从U 走到V 然后从V走回U  但是这并不是一个环
    算法:
    在floyd的同时,顺便算出最小环
       g[i][j]=(i,j之间的边长)
       dist:=g;
       for k:=1 to n do
        begin
          for i:=1 to k-1 do
            for j:=i+1 to k-1 do
                answer:=min(answer,dist[i][j]+g[i][k]+g[k][j]);
          for i:=1 to n do
             for j:=1 to n do
                 dist[i][j]:=min(dist[i][j],dist[i][k]+dist[k][j]);
        end;
       关于算法<2>的证明:
        一个环中的最大结点为k(编号最大),与他相连的两个点为i,j,这个环的最短长度为g[i][k]+g[k][j]+i到j的路径中,所有结点编号都小于k的最短路径长度
        根据floyd的原理,在最外层循环做了k-1次之后,dist[i][j]则代表了i到j的路径中,所有结点编号都小于k的最短路径
        综上所述,该算法一定能找到图中最小环。

    第二.求经过K条边的最短路径
    例题:给出了一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个节点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。
     有1 ≤ N ≤ 50,1 ≤ M ≤ 1000,1 ≤ W ≤ 100000,1 ≤ Q ≤ 100000
    这道题十分坑爹。
    题目里说好是无环图,但是数据里到处都是环。
    我刚开始想的方法是用SPFA拆点做
    把原图中每个点拆成N-1个点,分别表示经过I条边到达的这个点。因为最多经过N-1条边。
    数据中这种环就会像负权环一样导致SPFA永远做下去。

    但是暂且不管数据如何。对于这个题目,除了上面讲的SPFA 拆点的做法,FLOYD 也是可以很好解决的
    首先这个“密度”很特殊,IJ之间最小密度路径加上JK之间最小路径,不一定就是IK之间的最小密度路径。
    所以我们要先枚举经过了P条边 (1<=P<=N-1)

    定义状态f(i,j,k)表示从i到j恰好经过k条边的最短路,类似Floyd的算法得出DP方程:
            f(i,j,k)=Min{f(i,h,g)+f(h,j,k-g)}。
    这个方程是5维的,会超时,如何减小维数呢?
    考虑在何处重复决策。注意到f(i,j,k)的选择路径V1-V2-...-Vk,实际上我们只要找到这里的一个点决策即可,而不需每个点都判断过去。这样就很容易想到在最后一个点进行决策。
            f(i,j,k)=Min{f(i,h,k-1)+f(h,j,1)}。
    这样这个方法的时间复杂度就是0(N^4) 空间复杂度O(N^3)
    问题得到了很好的解决。


  • 相关阅读:
    Linux使用lrzsz上传下载文件
    开发Wordpress主题时没有特色图片的功能
    Windows10重启之后总是将默认浏览器设置为IE
    C#泛型类的类型约束
    CentOS给网站配置Https证书
    从微软官网下载VS离线安装包的方法
    Azure Sql Database为某个数据库创建单独的访问账户
    VS2017/2019 Product Key
    VMware Workstation/Fusion 14/15 密钥
    将DataTable进行分页并生成新的DataTable
  • 原文地址:https://www.cnblogs.com/firstrate/p/3262412.html
Copyright © 2011-2022 走看看