zoukankan      html  css  js  c++  java
  • poj1182、hdu1829(并查集)

    题目链接http://poj.org/problem?id=1182

    食物链
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 90077   Accepted: 27059

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
    有人用两种说法对这N个动物所构成的食物链关系进行描述:
    第一种说法是"1 X Y",表示X和Y是同类。
    第二种说法是"2 X Y",表示X吃Y。
    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
    1) 当前的话与前面的某些真的话冲突,就是假话;
    2) 当前的话中X或Y比N大,就是假话;
    3) 当前的话表示X吃X,就是假话。
    你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

    Input

    第一行是两个整数N和K,以一个空格分隔。
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
    若D=1,则表示X和Y是同类。
    若D=2,则表示X吃Y。

    Output

    只有一个整数,表示假话的数目。

    Sample Input

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    Sample Output

    3
    解题思路:题解来源于挑战程序设计,对于每只动物i创建3个元素i-A,i-B,i-C,并利用这3*N个元素建立并查集。这个并查集维护如下关系:

    i-x表示“i属于种类x“。
    并查集里的每一个组表示组内所有元素代表的情况都同时发生或不发生。

    例如,如果i-A和j-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。因此对于每一条信息,只需按照如下进行操作就可以了。
    第一种:x和y属于同一类,合并x-A和y-A,x-B和y-B,x-C和y-C。
    第二种:x吃y 合并x-A和y-B,x-B和y-C,x-C和y-A。

    不过在合并前,需要先判断合并是否会产生矛盾。例如在第一种情况下,需要先检查比如x-A和y-B或者y-C是否在同一组等信息。
    附上代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 const int maxn=400005;
     6 int n,k;
     7 int par[maxn];  //父亲
     8 int rank[maxn]; //树的高度
     9 
    10 //初始化n个元素
    11 void init(int n)
    12 {
    13     for(int i=0;i<n;i++)
    14     {
    15         par[i]=i;
    16         rank[i]=0;
    17     }
    18 }
    19 //查询树的根
    20 int find(int x)
    21 {
    22     if(par[x]==x)
    23         return x;
    24     else
    25         return par[x]=find(par[x]);
    26 }
    27 //合并x和y所属的集合
    28 void unite(int x,int y)
    29 {
    30     if(find(x)==find(y))
    31         return;
    32     else
    33     {
    34         if(rank[find(x)]<rank[find(y)])
    35             par[find(x)]=find(y);
    36         else
    37         {
    38             par[find(y)]=find(x);
    39             if(rank[find(x)]==rank[find(y)])
    40                 rank[find(x)]++;
    41         }
    42     }
    43 }
    44 //判断x和y是否在同一个集合
    45 bool same(int x,int y)
    46 {
    47     return find(x)==find(y);
    48 } 
    49 
    50 int main()
    51 {
    52     scanf("%d%d",&n,&k);
    53     //初始化并查集
    54     //元素x,x+n,x+2*n分别为x-A,x-B,x-C
    55     init(n*3);
    56     
    57     int ans=0;
    58     for(int i=0;i<k;i++)
    59     {
    60         int t,x,y;
    61         scanf("%d%d%d",&t,&x,&y);
    62         x-=1,y-=1;  //把输入变成0~n-1的范围
    63         //编号非法直接跳过
    64         if(x<0||x>=n||y<0||y>=n)
    65         {
    66             ans++;
    67             continue;
    68         }
    69         if(t==1)  //x和y属于同一类
    70         {
    71             if(same(x,y+n)||same(x,y+2*n))
    72                 ans++;
    73             else
    74             {
    75                 unite(x,y);
    76                 unite(x+n,y+n);
    77                 unite(x+n*2,y+n*2);
    78             }
    79         }
    80         else   //x吃y 
    81         {
    82             if(same(x,y)||same(x,y+2*n))
    83                 ans++;
    84             else
    85             {
    86                 unite(x,y+n);
    87                 unite(x+n,y+2*n);
    88                 unite(x+2*n,y);
    89             }
    90         }
    91     }
    92     printf("%d
    ",ans);
    93     return 0;
    94 } 

     相似题:hdu1829 A Bug's Life

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1829

    题目大意::给你n个虫,输入m行a,b,表示a和b是异性,要你判断是否有同性恋

    解题思路:类型基本一致,比那个更简单,情况就两种,同性和异性,建立两个集合就行,如果输入的a、b同时存在一个集合当中,说明他们就是同性恋了。

    附上代码:

     1 #include<stdio.h>
     2 int par[2000005],rank[2000005];
     3 
     4 void init(int x)
     5 {
     6     for(int i=1;i<=x;i++)
     7     {
     8         par[i]=i;
     9         rank[i]=0;
    10     }
    11 }
    12 
    13 int find(int x)
    14 {
    15     if(x==par[x])
    16         return x;
    17     else
    18         return par[x]=find(par[x]);
    19 }
    20 
    21 void unite(int x,int y)
    22 {
    23     int rootx=find(x);
    24     int rooty=find(y);
    25     if(x==y)
    26         return;
    27     if(rank[rootx]<rank[rooty])
    28         par[rootx]=rooty;
    29     else
    30     {
    31         par[rooty]=rootx;
    32         if(rank[rootx]==rank[rooty])
    33             rank[rootx]++;
    34     }
    35 }
    36 
    37 bool same(int x,int y)
    38 {
    39     return find(x)==find(y);
    40 }
    41 
    42 int main()
    43 {
    44     int t;
    45     scanf("%d",&t);
    46     int kase=1;
    47     while(t--)
    48     {
    49         int n,m;
    50         int flag=0;
    51         scanf("%d%d",&n,&m);
    52         init(n*2);
    53         while(m--)
    54         {
    55             int a,b;
    56             scanf("%d%d",&a,&b);
    57             unite(a,b+n);
    58             unite(a+n,b);
    59             if(same(a,b)||same(a+n,b+n))
    60                 flag=1;
    61         }
    62         printf("Scenario #%d:
    ",kase++);
    63         if(flag)
    64             printf("Suspicious bugs found!
    ");
    65         else
    66             printf("No suspicious bugs found!
    ");
    67         printf("
    ");
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    ORACLE数据库表解锁record is locked by another user
    Oracle11gR2设置连接数process与会话session值
    Oracle 11g用exp无法导出空表的处理方法
    Oracle随机选择一条记录SQL
    Oracle取查询结果数据的第一条记录SQL
    Hibernate 一对多查询对set的排序
    Windows平台下Oracle实例启动过程中日志输出
    Windows平台下Oracle监听服务启动过程中日志输出
    Windows平台下Oracle 11g R2监听文件日志过大,造成客户端无法连接的问题处理
    WebSphere设置会话超时时间
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/9417629.html
Copyright © 2011-2022 走看看