zoukankan      html  css  js  c++  java
  • 并查集专题2

    hdu 1829 A Bug's Life

    http://acm.hdu.edu.cn/showproblem.php?pid=1829

    解题思路:这个题目跟其他的不太一样,给出的不是同类而是异类,其实是差不多的。

    增加一个sex[i]表示i的异类,那么就是有两个集合,输入一组数据的时候判断一下两个是不是在同一个集合里,如果是那么输出Suspicious bugs found!

    一直没有输出No suspicious bugs found!

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxlen 2010
     5 using namespace std;
     6 int father[maxlen];
     7 int sex[maxlen];
     8 int n,m;
     9 void init()
    10 {
    11     for(int i=0; i<=n; ++i)
    12     {
    13         father[i]=i;
    14         sex[i]=0;
    15     }
    16 }
    17 int Find(int x)
    18 {
    19     return father[x]==x?x:father[x]=Find(father[x]);
    20 }
    21 void Union(int x ,int y)
    22 {
    23     x=Find(x),y=Find(y);
    24     if(x!=y)
    25         father[x]=y;
    26 }
    27 int main ()
    28 {
    29     int t;
    30     int x,y;
    31     scanf("%d",&t);
    32     for(int Case=1; Case<=t; ++Case)
    33     {
    34         int flag=1;
    35         scanf("%d%d",&n,&m);
    36         init();
    37         for(int i=0; i<m; ++i)
    38         {
    39             scanf("%d%d",&x,&y);
    40             if(Find(x)==Find(y))
    41                 flag=0;
    42             if(sex[x]==0)
    43                 sex[x]=y;
    44             else
    45                 Union(sex[x],y);
    46             if(sex[y]==0)
    47                 sex[y]=x;
    48             else
    49                 Union(sex[y],x);
    50         }
    51         printf("Scenario #%d:
    ",Case);
    52         if(flag)
    53             printf("No suspicious bugs found!
    
    ");
    54         else
    55             printf("Suspicious bugs found!
    
    ");
    56     }
    57 }
    View Code

     hdu 4496 D-City

    http://acm.hdu.edu.cn/showproblem.php?pid=4496

    解题思路:通化邀请赛的题目,并查集。

    题目说的是N个点M条边,现在让你输出的是删除前k条边后,这个图的联通分支数是多少。

    倒过来做,一开始的时候每个节点都是一个联通分支,所以分支数是N,然后每次加入一条边的时候,看一下这条边的两个端点是不是在同一个分支里,如果不是,合并并且分支数-1,将分支压入栈中。

    最后输出就可以了。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <stack>
     5 #define maxlen 10010
     6 using namespace std;
     7 int father[maxlen];
     8 int n,m;
     9 char str[100010];
    10 struct node
    11 {
    12     int s,e;
    13 }p[100010];
    14 void init()
    15 {
    16     for(int i=0;i<=n;++i)
    17         father[i]=i;
    18 }
    19 int inline Find(int x)
    20 {
    21     return father[x]==x?x:father[x]=Find(father[x]);
    22 }
    23 void inline Union(int x,int y)
    24 {
    25     x=Find(x),y=Find(y);
    26     if(x!=y)
    27         father[x]=y;
    28 }
    29 int main ()
    30 {
    31     while(scanf("%d%d",&n,&m)!=EOF)
    32     {
    33         for(int i=0;i<m;++i)
    34             scanf("%d%d",&p[i].s,&p[i].e);
    35         init();
    36         int cnt=n;
    37         stack<int>s;
    38         for(int i=m-1;i>=0;--i)
    39         {
    40             s.push(cnt);
    41             if(Find(p[i].s)!=Find(p[i].e))
    42             {
    43                 Union(p[i].s,p[i].e);
    44                 cnt--;
    45             }
    46         }
    47         while(!s.empty())
    48         {
    49             printf("%d
    ",s.top());
    50             s.pop();
    51         }
    52     }
    53 
    54 }
    View Code

     uva 11987 Almost Union-Find

    题目大意:

    给了三种操作:

    1 p q 合并

    2 p q 把p移动到q集合中

    3 p 求p所在集合的元素个数以及元素之和

    分析:

    关键就是第二个操作,事实上移动操作就是删除+合并操作。

    删除操作具体可以看我上一篇并查集专题最后一题

    可以增加一个id[i]数组表示i这个数现在真实的对应的下标,在删除操作的时候,将id改为新的虚拟父亲,从新初始化既可以了。

    其他两个值得维护也比较简单,就是在合并的是后把被合并的两个值加到合并的集合中去就可以了。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxlen 200010
     5 using namespace std;
     6 int father[maxlen],id[maxlen];
     7 int num[maxlen];
     8 long long sum[maxlen];
     9 int n,m;
    10 int cnt;
    11 void init()
    12 {
    13     for(int i=1;i<=n;++i)
    14     {
    15         id[i]=father[i]=sum[i]=i;
    16         num[i]=1;
    17     }
    18     cnt=n;
    19 }
    20 int Find(int x)
    21 {
    22     return father[x]==x?x:father[x]=Find(father[x]);
    23 }
    24 void Union(int x,int y)
    25 {
    26     x=Find(id[x]),y=Find(id[y]);
    27     father[x]=y;
    28     num[y]+=num[x];
    29     sum[y]+=sum[x];
    30 }
    31 void Delete(int x)
    32 {
    33     int xx=Find(id[x]);
    34     --num[xx];
    35     sum[xx]-=x;
    36     id[x]=(++cnt);//从新初始化
    37     father[id[x]]=id[x];
    38     num[id[x]]=1;
    39     sum[id[x]]=x;
    40 }
    41 int main()
    42 {
    43     while(scanf("%d%d",&n,&m)!=EOF)
    44     {
    45         init();
    46         for(int i=0;i<m;++i)
    47         {
    48             int cmd,x,y;
    49             scanf("%d",&cmd);
    50             if(cmd==1)
    51             {
    52                 scanf("%d%d",&x,&y);
    53                 if(Find(id[x])!=Find(id[y]))
    54                     Union(x,y);
    55             }
    56             else if(cmd==2)
    57             {
    58                 scanf("%d%d",&x,&y);
    59                 if(Find(id[x])!=Find(id[y]))
    60                 {
    61                     Delete(x);
    62                     Union(x,y);
    63                 }
    64             }
    65             else 
    66             {
    67                 scanf("%d",&x);
    68                 x=Find(id[x]);
    69                 printf("%d %lld
    ",num[x],sum[x]);
    70             }
    71         }
    72     }
    73 }
    View Code
  • 相关阅读:
    Hadoop无法访问web50070端口
    Hadoop问题汇总
    Hadoop问题汇总
    Linux网络连接模式以及修改静态IP
    Linux网络连接模式以及修改静态IP
    Linux基本命令
    SQLite数据操作
    SQLite初试
    编码与解码
    属性列表
  • 原文地址:https://www.cnblogs.com/shuzy/p/3253823.html
Copyright © 2011-2022 走看看