zoukankan      html  css  js  c++  java
  • Floyd最小环

    本文转自这里

      最小环:从一个点出发,经过一条简单路径回到起点成为环.图的最小环就是所有环中长度最小的.

      怎样求最小环呢?

      1传统的解决方法(dijkstra):
            任意一个最小环环的权值,我们都可以看成两个有边相连的结点i、j的直接距离加上i、j间不包含边(边i->j)的最短路径。求最短路径我们第一个想到的就Dijkstra算法。而Dijkstra所求的是一个点到所有点的最短距离。用Dijkstra所求的i、j的最短距离一定是i、j的直接距离(如果i,j连通),所以我们需要先将i、j的边从图中删除(若i,j不连通,则不用删除),再用Dijkstra求新图中i、j的最短距离即可。所以我们每次在图中选取一条边,把它从图中删掉.然后对删掉的那条边所对应的2点进行Dijkstra,也就是m次Dijkstra。

      2.floyd求最小环:

            抛开Dijkstra算法,进而我们想到用Floyd算法。我们知道,Floyd算法在进行时会不断更新矩阵dist(k)。设dist[k,i,j]表示从结点i到结点j且满足所有中间结点,它们均属于集合{1,2,⋯ ,k}的一条最短路径的权。其中dist[0,i,j ]即为初始状态i到j的直接距离。对于一个给定的赋权有向图, 求出其中权值和最小的一个环。我们可以将任意一个环化成如下形式:u->k->v ->(x1-> x2-> ⋯ xm1)-> u(u与k、k与v都是直接相连的),其中v ->(x1-> 2-> ⋯ m)-> u是指v到u不经过k的一种路径。

            在u,k,v确定的情况下,要使环权值最小, 则要求 (x1一>x2->⋯一>xm)->u路径权值最小.即要求其为v到u不经过k的最短路径,则这个经过u,k,v的环的最短路径就是:[v到u不包含k的最短距离]+dist[O,u,k]+dist[O,k,v]。我们用Floyd只能求出任意2点间满足中间结点均属于集合{1,2,⋯ ,k}的最短路径,可是我们如何求出v到u不包含k的最短距离呢?
             现在我们给k加一个限制条件:k为当前环中的序号最大的节点(简称最大点)。因为k是最大点,所以当前环中没有任何一个点≥k,即所有点都<k。因为v->(x1->x2->......xm)->u属于当前环,所以x1,x2,⋯ ,xm<k,即x1,x2.⋯。xm≤k一1。这样,v到u的最短距离就可以表示成dist[k一1 ,u,v]。dist[k一1,v,u]表示的是从v到u且满足所有中间结点均属于集合{1,2,⋯ ,k一1}的一条最短路径的权。接下来,我们就可以求出v到u不包含k的最短距离了。这里只是要求不包含k,而上述方法用的是dist[k一1,v,u],求出的路径永远不会包含k+l,k+2,⋯ 。万一所求的最小环中包含k+1,k+2,⋯ 怎么办呢?的确,如果最小环中包含比k大的节点,在当前u,k,v所求出的环显然不是那个最小环。然而我们知道,这个最小环中必定有一个最大点kO,也就是说,虽然当前k没有求出我们所需要的最小环,但是当我们从k做到kO的时候,这个环上的所有点都小于kO了.也就是说在k=kO时一定能求出这个最小环。我们用一个实例来说明:假设最小环为1—3—4—5—6—2—1。的确,在u=l,v=4,k=3时,k<6,dist[3,4,1]的确求出的不是4—5—6—2—1这个环,但是,当u=4,v=6,k=5或u=5,v=2,k=6时,dist[k,v,u]表示的都是这条最短路径.所以我们在Floyd以后,只要枚举u.v,k三个变量即可求出最小环。时间复杂度为O(n3)。我们可以发现,Floyd和最后枚举u,v,k三个变量求最小环的过程都是u,v,k三个变量,所以我们可以将其合并。这样,我们在k变量变化的同时,也就是进行Floyd算法的同时,寻找最大点为k的最小环。

    POJ 1734  

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define _Clr(x, y) memset(x, y, sizeof(x))
     5 #define INF 0xfffffff
     6 #define N 110
     7 using namespace std;
     8 
     9 int mat[N][N], dist[N][N];
    10 int next[N][N]; // next[i][j]表示i到j经历的第一个点。
    11 int path[N];
    12 int cnt, n;
    13 
    14 void Floyd()
    15 {
    16     int mins=INF;
    17     for(int k=1; k<=n; k++)
    18     {
    19         for(int i=1; i<k; i++)
    20         for(int j=i+1; j<k; j++)
    21         {
    22             int tmp = dist[i][j]+mat[i][k]+mat[k][j];
    23             if(tmp < mins)// 更新最小环的权值
    24             {
    25                 mins = tmp;
    26                 cnt=0;
    27                 int p = i;
    28                 while(p!=j) // 记录最小环的路径
    29                 {
    30                     path[cnt++] = p;
    31                     p = next[p][j];
    32                 }
    33                 path[cnt++] = j;
    34                 path[cnt++] = k;
    35             }
    36         }
    37         for(int i=1; i<=n; i++)
    38         for(int j=1; j<=n; j++)
    39         {
    40             if(dist[i][k]+dist[k][j] < dist[i][j])
    41             {
    42                 dist[i][j] = dist[i][k] + dist[k][j];
    43                 next[i][j] = next[i][k];
    44             }
    45         }
    46     }
    47     if(mins==INF)
    48         puts("No solution.");
    49     else
    50     {
    51         for(int i=0; i<cnt; i++)
    52             printf("%d%s", path[i], i==cnt-1 ? "
    ":" ");
    53     }
    54 }
    55 
    56 void Init()
    57 {
    58     for(int i=1; i<=n; i++)
    59     for(int j=1; j<=n; j++)
    60     {
    61         mat[i][j] = dist[i][j] = INF;
    62         next[i][j] = j;
    63     }
    64 }
    65 int main()
    66 {
    67     int m, a, b, c;
    68     while(~scanf("%d%d", &n, &m))
    69     {
    70         Init();
    71         while(m--)
    72         {
    73             scanf("%d%d%d", &a, &b, &c);
    74             if(c < mat[a][b])
    75             {
    76                 mat[a][b] = mat[b][a] = c;
    77                 dist[a][b] = dist[b][a] = c;
    78             }
    79         }
    80         Floyd();
    81     }
    82     return 0;
    83 }
    View Code
  • 相关阅读:
    Linux之开源软件移植
    数学问题的解题方法(模板)
    图论相关算法理解和总结
    关于ACM,关于CSU
    hdu 4607(树的直径)
    树的直径
    SGU-181 X-Sequence
    1629 B君的圆锥
    1134 最长递增子序列(暴力写的)
    1483 化学变换(暴力)
  • 原文地址:https://www.cnblogs.com/khan724/p/4383686.html
Copyright © 2011-2022 走看看