zoukankan      html  css  js  c++  java
  • 食物链(带权&种类并查集)

    食物链

    http://poj.org/problem?id=1182
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 93264   Accepted: 28135

    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



    一道经典的并查集题目
    这是用带权并查集做的代码
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<string>
     7 #include<queue>
     8 #include<vector>
     9 #include<set>
    10 using namespace std;
    11 
    12 int n,k;
    13 int fa[50005];
    14 int dis[50005];
    15 
    16 int Find(int x){
    17     if(x!=fa[x]){
    18         int xx=fa[x];
    19         fa[x]=Find(fa[x]);
    20         dis[x]=(dis[x]+dis[xx])%3;
    21     }
    22     return fa[x];
    23 }
    24 
    25 int main(){
    26 
    27     int n,k;
    28     ///0表示同类,1表示x吃y,2表示y吃x
    29     scanf("%d %d",&n,&k);
    30     for(int i=1;i<=n;i++){
    31         fa[i]=i;
    32         dis[i]=0;
    33     }
    34     int ans=0;
    35     int pos,x,y;
    36     for(int i=1;i<=k;i++){
    37         scanf("%d %d %d",&pos,&x,&y);
    38         if(pos==2&&x==y){
    39             ans++;
    40         }
    41         else if(x>n||y>n){
    42             ans++;
    43         }
    44         else{
    45             if(pos==1){///同类
    46                 if(Find(x)==Find(y)){///在一个并查集中
    47                     if(dis[x]!=dis[y]){
    48                         ans++;
    49                     }
    50                 }
    51                 else{
    52                     dis[fa[x]]=(dis[y]-dis[x]+3)%3;
    53                     fa[fa[x]]=fa[y];
    54                 }
    55             }
    56             else{///x吃y
    57                 if(Find(x)==Find(y)){
    58                     if(dis[x]!=(dis[y]+1)%3){
    59                         ans++;
    60                     }
    61                 }
    62                 else{
    63                     dis[fa[x]]=(dis[y]-dis[x]+4)%3;
    64                     fa[fa[x]]=fa[y];
    65                 }
    66 
    67             }
    68         }
    69     }
    70     printf("%d
    ",ans);
    71 }
    View Code

     

    这是用种类并查集做的代码
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<string>
     7 #include<queue>
     8 #include<vector>
     9 #include<set>
    10 using namespace std;
    11 
    12 int n,k;
    13 int fa[50005*3];
    14 
    15 int Find(int x){
    16     int r=x,y;
    17     while(x!=fa[x]){
    18         x=fa[x];
    19     }
    20     while(r!=x){
    21         y=fa[r];
    22         fa[r]=x;
    23         r=y;
    24     }
    25     return x;
    26 }
    27 
    28 int main(){
    29 
    30     scanf("%d %d",&n,&k);
    31     int ans=0;
    32     for(int i=1;i<=n*3;i++){
    33         fa[i]=i;
    34     }
    35     int pos,x,y;
    36     for(int i=1;i<=k;i++){
    37         scanf("%d %d %d",&pos,&x,&y);
    38         if(x>n||y>n) {
    39             ans++;
    40             continue;
    41         }
    42         if(pos==1){///同类
    43             if(Find(x)==Find(y+n)||Find(y)==Find(x+n)) ans++;
    44             else{
    45                 fa[Find(x)]=Find(y);
    46                 fa[Find(x+n)]=Find(y+n);
    47                 fa[Find(x+n+n)]=Find(y+n+n);
    48             }
    49         }
    50         else{///x吃y
    51             if(x==y){
    52                 ans++;
    53             }
    54             else{
    55                 if(Find(x)==Find(y)||Find(x+n)==Find(y)) ans++;
    56                 else{
    57                     fa[Find(x)]=Find(y+n);
    58                     fa[Find(x+n)]=Find(y+n+n);
    59                     fa[Find(x+n+n)]=Find(y);
    60                 }
    61             }
    62         }
    63     }
    64     printf("%d
    ",ans);
    65 }
    View Code
  • 相关阅读:
    Java线程
    腾讯2012.9.23校园招聘笔试题
    腾讯2011.10.15校园招聘笔试题
    腾讯2013年实习生笔试题目
    腾讯2012.4.25实习生招聘笔试题(2)
    腾讯2012.4.25实习生招聘笔试题
    优酷土豆2012.9.12校园招聘笔试题
    谷歌面试题:在半径为1的圆中随机选取一点
    Reservoir Sampling
    微软面试15道
  • 原文地址:https://www.cnblogs.com/Fighting-sh/p/9693745.html
Copyright © 2011-2022 走看看