zoukankan      html  css  js  c++  java
  • 求最小环 —— 并查集 与 Floyd

    对于一个图,如何求出其中的最小环(不包括一元环)?

    很显然,对于一个无向图,每一条边都是一个二元环;对于有向图,可以考虑从每一个点出发,用DFS求出它到自己的距离,如果遍历了$N$个点仍未便利到自己,则该点不在环中。但是这样做的复杂度非常感人……如果没有分析错的话最坏应该是$O(n^2 m)$

    可以考虑有一些优化, 对于一个点,如果它在一个环中,那么它在该环上dfs过的点一定在环中。在回溯一个点的过程中,如果搜到环,那么在搜下一个点的时候就不清空他们的标记数组。对于搜不到环的点,它的入度一定为一,如果不为一,那么删除它入边所连的入度为零的点后入度为零。所以可以预处理,删除入度为零的点和它所连的边(如果后面还有用就标记),然后再按照上述方式dfs,时间复杂度为$O(nm)$

    但是对于稠密图,复杂度还是太高,甚至高过$O(n^3)$,这听起来是不是有些耳熟? 没错,Floyd。

    用 $k$ 作为当前搜索点,不断求出其它点的最短路径和路经所在环长,即

       $dis[i][j] = std::max(dis[i][j], dis[i][k], dis[j][k]), ans = std::max(ans, dis[i][j]+G[k][i]+G[j][k]); // G[][] 为邻接矩阵$

    时间复杂度为 $O(N^3)$

    当然,在$N>1000$的稠密图中,这种方法的复杂度依然很感人。

    由于连边的关系也可以看作是树中“父与子”的关系,则可以使用并查集,通过路径压缩求出在某一图中的环,若存在两个连边的点在同一并查集中,那么一定有环,环的权值为两点到祖先的权值和加1。

    为什么这样是对的呢? 在一个路径已经被压缩的树中,任意两节点在图中一定相连,当某一点的父节点成为该点的子节点时,该点一定在环上。只要没有重边,那么该方法一定适用。

    Floyd 代码:

    int G[N][N], dis[N][N];
    int main(){
        for(int k = 1; k <= n; k++){
        for(int i=1;i<=k-1;i++)    
             for(int j=i+1;j<=k-1;j++)
                  ans = std::max(ans, dis[i][j]+G[k][i]+G[k][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
              dis[i][j] = std::max(dis[i][j], G[i][k]+G[k][j]);                   
        }
       //...                             
        return 0;
    }

    并查集代码

     1 int find(int x){ 
     2     if(f[x] != x){
     3         int o = f[x];
     4         f[x] = find(f[x]);
     5         d[x] += d[o];
     6     }
     7     return f[x];
     8 }
     9 int main(){
    10   scanf("%d", &n);
    11   for(int i=1;i<=n;i++) f[i] = i;
    12   for(int i=1;i<=n;i++){
    13     scanf("%d", &x);
    14     int a = find(i), b = find(x);
    15     if(a != b) { f[a] = b; d[i] = d[x]+1; }
    16     else  min = std::min(min, d[x] + d[i] + 1);
    17   }
    18   printf("%d
    " ,min);
    19   return 0;
    20 }

     来写个裸题练练吧!https://www.luogu.org/problemnew/show/P2661

  • 相关阅读:
    TCP/IP协议,,OSI的七层参考模型,HTTP请求响应机制
    火狐浏览器缓存导致JS已经改变的ID没改变
    Server.MapPath 出现未将对象引用设置到对象的实例
    线程池发送邮件的方法(向多个用户发送同一邮件)
    用多线程发送邮箱(一次给一个用户发送N封邮件)
    验证文本框输入内容类型是汉字
    名人博客
    tinyget
    内存分析
    Silverlight Forums
  • 原文地址:https://www.cnblogs.com/fseject-2002/p/9724557.html
Copyright © 2011-2022 走看看