zoukankan      html  css  js  c++  java
  • poj1703 并查集,维护不同集合

    题目大意:

    警方决定捣毁两大犯罪团伙:龙帮和蛇帮,显然一个帮派至少有一人。该城有N个罪犯,编号从1至N(N<=100000。将有M(M<=100000)次操作。
    D a b 表示a、b是不同帮派
    A a b 询问a、b关系

    对于每一个A操作,回答"In the same gang."或"In different gangs." 或"Not sure yet."

    (大意摘自vjudge)

    题解:维护不同集合关系的经典题目,和poj食物链那道题一样

    可参考https://blog.csdn.net/freezhanacmore/article/details/8774033

    直接上代码

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 const int maxn=1e5+100;
     6 int head=0,tail=10002;
     7 int n,m;
     8 int father[maxn*2],rank[maxn*2],vis[maxn*2];
     9 int findf(int x)
    10 {
    11     int k, j, r;
    12     r = x;
    13     while(r != father[r])
    14         r = father[r];
    15     k = x;
    16     while(k != r)
    17     {
    18         j = father[k];
    19         father[k] = r;
    20         k = j;
    21     }
    22     return r;
    23 }
    24 
    25 void merg(int x,int y)
    26 {
    27     int fx=findf(x);
    28     int fy=findf(y);
    29     if(rank[fx]<=rank[fy])
    30     {
    31         father[fy]=fx;
    32         rank[fx]++;
    33     }
    34     else
    35     {
    36         father[fx]=fy;
    37         rank[fy]++;
    38     }
    39 }
    40 void ini()
    41 {
    42     for(int i=0;i<=2*maxn;i++) father[i]=i;
    43     father[tail]=tail;
    44     memset(rank,0,sizeof(rank));
    45 }
    46 void solve()
    47 {
    48     scanf("%d%d",&n,&m);
    49     ini();
    50     for(int i=1;i<=m;i++)
    51     {
    52         char a;int b,c;
    53         cin>>a;scanf("%d%d",&b,&c);
    54         if(a=='A')
    55         {
    56             //for(int i=1;i<=n;i++) printf("%d ",father[i]);puts("");
    57                 if(findf(b)==findf(c)||findf(b+n)==findf(c+n))
    58                     puts("In the same gang.");
    59                 else if(findf(b)==findf(c+n)||findf(c)==findf(b+n))
    60                     puts("In different gangs.");
    61                 else puts("Not sure yet.");
    62         }
    63         else
    64         {
    65             merg(b,c+n);
    66             merg(c,b+n);
    67         }
    68     }
    69 }
    70 
    71 int main()
    72 {
    73     //freopen("in.txt","r",stdin);
    74     int T;
    75     cin>>T;
    76     for(int i=1;i<=T;i++) solve();
    77 }
    View Code

    思路:除了像普通的并查集定义一个 p[] 记录父亲节点外,还定义一个 r[] 记录当前点与其所属的连通分量的根节点的关系。            r[] = 0 表示属于同一个帮派; r[] = 1表示与其根节点属于不同的帮派。                       开始时初始化自己是自己的父亲 p[x] = x,自己与自己属于同一类 r[x] = 0.           一旦输入 D 断定 x 和 y 属于不同集合后,就连接 x 和 y 所在的树,同时更新 r[]           一旦输入 A           如果 find(x) 不等于 find(y) 说明还没有判断过 x 与 y 直接输出关系不确定即可      Not sure yet.      如果find(x)等于 find(y) ,但是他们的r不等,说明属于不同帮派,输出In different gangs.                               如果他们的r相等,说明属于同一个帮派,则输出In the same gang注意:1.find()函数寻找根节点的时候要不断的更新 r         根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系       如果 a 和 b 的关系是 r1, b 和 c 的关系是 r2,       那么 a 和 c 的关系就是 (r1+r2)%2 . PS:因为只用两种情况所以对 2 取模。       如果实在不好理解,那么我们就枚举推理一下,共有 2*2 = 4种情况:       (a, b) (b, c)  (a, c)  (r1+r2)%2          0 0       0        0        a 和 b是同类 , b 和 c 是同类, 所以 a 和 c 也是同类          0      1       1        1        a 和 b是同类 , b 和 c 是异类, 所以 a 和 c 也是异类          1      0       1        1        a 和 b是异类 , b 和 c 是同类, 所以 a 和 c 是异类          1      1       0        0        a 和 b是异类 , b 和 c 是异类, 所以 a 和 c 是同类     2.Union()联合两棵树的时候也要更新两棵树的根的关系       定义:fx 为 x的根节点, fy 为 y 的根节点       联合时,使得 p[fx] = fy; 同时也要寻找 fx 与 fy 的关系。关系为:(r[x]+r[y]+1)%2       如何证明?       fx 与 x 的关系是 r[x],        x 与 y 的关系是 1 (因为确定是不同类,才联合的),        y 与 fy 关系是 r[y],模 2 是因为只有两种关系       所以又上面的一点所推出的定理可以证明 fx 与 fy 的关系是: (r[x]+r[y]+1)%2--------------------- 作者:cfreezhan 来源:CSDN 原文:https://blog.csdn.net/freezhanacmore/article/details/8774033 版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    查找和排序-6.快速排序
    查找和排序-5.插入排序
    PAT (Basic Level) Practice (中文)1093、1094
    srand((unsigned)time(NULL))详解
    fscanf()库函数
    C++ fopen函数用法
    简单计数排序
    数据结构:堆排序
    数据结构:归并排序
    团体程序设计天梯赛-练习集(八)(DFS,7-37 整数分解为若干项之和、7-22 龟兔赛跑)
  • 原文地址:https://www.cnblogs.com/codeoosacm/p/10078856.html
Copyright © 2011-2022 走看看