zoukankan      html  css  js  c++  java
  • P2024 [NOI2001]食物链[扩展域并查集]

    题目来源:洛谷

    题目描述

    动物王国中有三类动物 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 句话有的是真

    的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

    • 当前的话与前面的某些真的话冲突,就是假话

    • 当前的话中 X 或 Y 比 N 大,就是假话

    • 当前的话表示 X 吃 X,就是假话

    你的任务是根据给定的 N 和 K 句话,输出假话的总数。

    输入输出格式

    输入格式:

    从 eat.in 中输入数据

    第一行两个整数,N,K,表示有 N 个动物,K 句话。

    第二行开始每行一句话(按照题目要求,见样例)

    输出格式:

    输出到 eat.out 中

    一行,一个整数,表示假话的总数。

    输入输出样例

    输入样例#1: 
    100 7
    1 101 1
    2 1 2
    2 2 3
    2 3 3
    1 1 3
    2 3 1
    1 5 5
    
    输出样例#1: 
    3
    

    说明

    1 ≤ N ≤ 5 ∗ 10^4

    1 ≤ K ≤ 10^5

    解析:

    好题啊好题啊(啪啪啪)!干了我一天终于出来了。

    一开始想用边带权并查集解,发现本蒟蒻想不出来,还是用了扩展域。

    这题可以看作 P1525 关押罪犯 的一个延伸拓展题目,具体思路是差不多的。


    如果对扩展域有疑问,可以看我以前的一篇题解 P1525 关押罪犯[扩展域并查集],里面有提到扩展域。

    思路:

     扩展域并查集维护三个域:x_self同类,x_enemy天敌,x_eat捕食。

    他们之间的关系:

    假设有x,y两个动物,

    如果题目给定x和y是同类,那么合并x_self,y_self和x_enemy,y_enemy和x_eat和y_eat。

    前提条件是:x_self与y_eat不在同一个集合,x_eat与y_self不在同一个集合。

    如果题目给定x吃y,这里我们注意到一点,由于题目给出的食物链关系是环形,因此我们可以由“x吃y”推断出“x的天敌是y的猎物”

    由此得到,合并x_eat,y_self和x_self,y_enemy和x_enemy,y_eat。

    前提条件是:x_self和y_self不在一个集合,x_self和y_eat不在一个集合。

    参考代码:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 #include<cstring>
     5 #include<iostream>
     6 #define N 50010
     7 using namespace std;
     8 struct node{
     9     int x,y,flag;
    10 }g[N<<4];
    11 int n,k,fa[N<<4];
    12 int get(int x)
    13 {
    14     if(fa[x]==x) return x;
    15     return fa[x]=get(fa[x]);
    16 }
    17 void merge(int x,int y)
    18 {
    19     x=get(x),y=get(y);
    20     fa[x]=y;
    21 }
    22 int main()
    23 {
    24     //freopen("fuc.in","r",stdin);
    25     //freopen("fuc.out","w",stdout);
    26     int cnt=0;
    27     scanf("%d%d",&n,&k);
    28     for(int i=1;i<=n*3;i++) fa[i]=i;
    29     for(int i=1;i<=k;i++)
    30         scanf("%d%d%d",&g[i].flag,&g[i].x,&g[i].y);
    31     for(int i=1;i<=k;i++){
    32         if(g[i].x>n||g[i].y>n){
    33             cnt++;continue;
    34         }
    35         int x_self=g[i].x,x_enemy=g[i].x+n,x_eat=g[i].x+n+n;
    36         int y_self=g[i].y,y_enemy=g[i].y+n,y_eat=g[i].y+n+n;
    37         if(g[i].flag==1){
    38             if(get(x_eat)==get(y_self)||get(x_self)==get(y_eat)){
    39                 cnt++;
    40             }
    41             else{
    42                 merge(x_self,y_self);
    43                 merge(x_eat,y_eat);
    44                 merge(x_enemy,y_enemy);
    45             }
    46         }
    47         else{
    48             if(get(x_self)==get(y_self)||get(y_eat)==get(x_self)){
    49                 cnt++;
    50             }
    51             else{
    52                 merge(x_self,y_enemy);
    53                 merge(x_eat,y_self);
    54                 merge(x_enemy,y_eat);
    55             }
    56         }
    57     }
    58     cout<<cnt<<endl;
    59     return 0;
    60 }
  • 相关阅读:
    CF1452F Divide Powers 题解
    ZOJ3705Applications
    ZOJ3706Break Standard Weight
    关于技术的感悟与规划
    做自己不愿做的事叫成长,做以前不敢做的事叫突破
    CSS之盒模型
    js数组的sort排序详解
    C#接口
    jQuery UI Dialog:Demo1:入门
    CSS之position解释
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/10979331.html
Copyright © 2011-2022 走看看