zoukankan      html  css  js  c++  java
  • 并查集

    并查集是一种数据结构,一般用来解决连通性或者动态连通性的问题。

    动态连通性:

    即一个图有n个结点,不断加入边,问此时任意两个结点的连通性。

    建模思路:

    对于连通的结点它们属于一个组,不连通的结点就属于不同的组。对于每一条边的输入,

    判断两个结点是否连通,如果不连通则将两个结点所属的两个组连成一个组。对于每一个组,设置一个组标志。

    初始时,任意两个结点不连通,组标志就是自己。

    for(i=0; i<n; ++i)
        father[i] = i;

    组的体现形式:

    连通的结点属于一个组,那么组内是怎么体现的呢?

    是用树来实现的

    左边一个组,组的标志是a,右边一个组,组的标志是e

    然后father[b] = a,father[c] = a, father[d] = d;

    如果每个结点的终极祖先相同,那么就是一个组。
    查找结点属于哪一个组的算法find

    1 int find(int x)
    2 {
    3     if(x==parent[x]) return x;//如果自己的父亲是自己,那么就是这个组的标志
    4     return find(parent[x]);//否则,看父亲的父亲是不是组的标志
    5 }

    如果输入一条边u-->v。如果u和v不属于一个组,那么就把两个组变成一个组

    1 int Union(int u, int v)
    2 {
    3     int ru = find(u);
    4     int rv = find(v);
    5     if(ru != rv)
    6     {
    7         parent[ru] = rv;
    8     }
    9 }


    但是会发生一个问题,那就是极端下,树的高度可能会很极端

    所以要进行路径压缩,即在find()函数返回的过程中,修改father数组

    1 int find(int x)
    2 {
    3     if(x==parent[x]) return x;//如果自己的父亲是自己,那么就是这个组的标志
    4     return parent[x] = find(parent[x]);//返回的过程中修改father数组,路径压缩
    5 }

    可是仍然存在问题,如果Union很多次,才find一次,那么极端情况下,情况仍然不理想,所以就存在按秩合并

    低的树指向高的树,不会增加书高,即按秩合并

     1 int Union(int u, int v)
     2 {
     3     int ru = find(u);
     4     int rv = find(v);
     5     if(ru != rv)
     6     {
     7         if(rank[ru] <= rank[rv])
     8         {
     9             parent[ru] = rv;
    10             if(rank[ru]==rank[rv])
    11                 rank[rv]++;
    12         }
    13         else
    14             parent[rv] = ru;
    15     }
    16 }

    种类并查集题目:

    http://poj.org/problem?id=1703

     1 /*
     2 有两个犯罪团伙,即两个种类。
     3 当出现 D A B 时,如果A,B不在一个集合内,那就合并A,B所在的集合,
     4 并且修改r数组
     5 r[x] = 0 表示x和father[x] 是同一种类  
     6 r[x] = 1 表示x和father[x] 不是同一种类
     7 */
     8 #include <stdio.h>
     9 #include <string.h>
    10 const int N = 100000 + 10;
    11 int father[N];
    12 int r[N];
    13 void init(int n)
    14 {
    15     for(int i=1; i<=n; ++i)
    16     {
    17         father[i] = i;
    18         r[i] = 0;
    19     }    
    20     
    21 }
    22 int find(int x)
    23 {
    24     if(x==father[x]) return x;
    25     else
    26     {
    27         int t = find(father[x]);
    28         r[x] = (r[x] + r[father[x]]) % 2;//路径压缩时,要修改r数组。画个图,很好推
    29         father[x] = t;
    30         return t;
    31     }
    32 }
    33 int main()
    34 {
    35     int n,m,i,a,b,fa,fb,t;
    36     char op;
    37     scanf("%d",&t);
    38     while(t--)
    39     {
    40         scanf("%d%d",&n,&m);
    41         init(n);
    42         for(i=0; i<m; ++i)
    43         {
    44             getchar();
    45             op = getchar();
    46             scanf("%d%d",&a,&b);
    47             
    48             fa = find(a); fb = find(b);
    49             if(op=='A')
    50             {
    51                 if(fa!=fb)
    52                     printf("Not sure yet.
    ");
    53                 else if((r[a]+r[b])%2!=0)//画个图就推出来了
    54                     printf("In different gangs.
    ");
    55                 else
    56                     printf("In the same gang.
    ");
    57             }
    58             else
    59             {
    60                 
    61                 if(fa!=fb)
    62                 {
    63                     father[fa] = fb;
    64                 }    r[fa] = (r[a] + r[b] + 1)%2;//画个图就推出来了
    65             }
    66         }
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    mysql学习笔记
    SpringMVC和Spring父子容器关系
    hexo部署在码云中 无样式问题 冷哈哈
    Mule 动态添加Endpoint(二)
    Mule 动态添加Endpoint
    关于Depend war包的总结
    Mule 控制Service的启/止
    Spring 接管 Hibernate 配置 延迟加载(总结)
    Spring操作指南AOP基本示例(基于XML)
    Spring操作指南AOP基本示例(基于注解)
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4295439.html
Copyright © 2011-2022 走看看