zoukankan      html  css  js  c++  java
  • [ACM] poj 1182 食物链(并查集)

    食物链
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 41200   Accepted: 11988

    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”。
    并查集里的每一个组表示组内所有元素代表的情况都同时发生或不发生。(对这道题这很真要,要考虑明白)

    只需进行如下操作:
    第一种,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。
    合并之前需先检查1是否在不在同一组2是否在同一组或反被吃。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <cmath>
     6 
     7 using namespace std;
     8 const int Max_n=50002;
     9 int a[Max_n*3],h[Max_n*3];
    10 void init(int n)//初始化每个元素自己为一个集合
    11 {
    12     for(int i=0;i<=n;i++)
    13     {
    14         a[i]=i;
    15         h[i]=0;
    16     }
    17 }
    18 int findx(int x)//查找树根
    19 {
    20     if(a[x]==x)
    21         return x;
    22     else
    23         return a[x]=findx(a[x]);//缩短树,在查找过程中直接找到树的根节点 
    24 }
    25 /*int findx(int x)//简写代码
    26 {
    27     return a[x]==x?x:findx(a[x]);
    28 }*/
    29 void unite(int x,int y)//合并两元素所在树(去除最糟情况)
    30 {
    31     x=findx(x);
    32     y=findx(y);
    33     if(x==y)return;
    34     if(h[x]<h[y])
    35         a[x]=y;
    36     else
    37     {
    38         a[y]=x;
    39         if(h[x]==h[y])h[x]++;
    40     }
    41 }
    42 /*void unite(int x,int y)//简化代码
    43 {
    44     x=findx(x);
    45     y=findx(y);
    46     if(x==y)
    47         return;
    48     a[x]=y;
    49 }*/
    50 bool same(int x,int y)//判断两元素是在同一集合里
    51 {
    52     if(findx(x)==findx(y))
    53         return true;
    54     else
    55         return false;
    56 }
    57 int main()
    58 {
    59     int n,m;
    60     scanf("%d %d",&n,&m);
    61     int d,x,y,ans=0;
    62     init(n*3);
    63     while(m--)
    64     {
    65         scanf("%d %d %d",&d,&x,&y);
    66         if(x<=0||y<=0||n<x||n<y||(d==2&&x==y))//排除错误输入
    67         {
    68             ans++;
    69             continue;
    70         }
    71         if(d==1)
    72         {
    73             if(same(x,y+n)||same(x,y+2*n))//以确定不在同一集合里
    74                 ans++;
    75             else
    76             {
    77                 unite(x,y);
    78                 unite(x+n,y+n);
    79                 unite(x+n*2,y+n*2);
    80             }
    81         }
    82         else
    83         {
    84             if(same(x,y)||same(x,y+2*n))//以确定为同一种动物或y吃x
    85                 ans++;
    86             else
    87             {
    88                 unite(x,y+n);
    89                 unite(x+n,y+2*n);
    90                 unite(x+n*2,y);
    91             }
    92         }
    93     }
    94     printf("%d
    ",ans);
    95 
    96     return 0;
    97 }
    AC代码
  • 相关阅读:
    初认识AngularJS
    (imcomplete) UVa 10127 Ones
    UVa 10061 How many zero's and how many digits?
    UVa 11728 Alternate Task
    UVa 11490 Just Another Problem
    UVa 10673 Play with Floor and Ceil
    JSON对象和字符串的收发(JS客户端用typeof()进行判断非常重要)
    HTML.ActionLink 和 Url.Action 的区别
    EASYUI TREE得到当前节点数据的GETDATA方法
    jqueery easyui tree把已选中的节点数据拼成json或者数组(非常重要)
  • 原文地址:https://www.cnblogs.com/vivider/p/3666146.html
Copyright © 2011-2022 走看看