zoukankan      html  css  js  c++  java
  • 【NOI2001】【洛谷P2024】食物链

    问题描述

    输入格式

    输出格式

    样例输入

    100 7

    1 101 1

    2 1 2

    2 2 3

    2 3 3

    1 1 3

    2 3 1

    1 5 5

    样例输出

    3

    数据范围

    题解

    动物王国的动物分为三个集合A,B,C,其中A吃B,B吃C,C吃A。我们用并查集表示这些集合间的关系

    对于两个动物x,y,它们之间存在3种关系,即x,y是同类,x吃y,或y吃x

    我们不知道两个动物是A,B,C中的哪两种,但是我们知道它们之间的关系一定在以上3种关系之间

    对于一个动物x,不妨设x+n表示吃x的动物所在的集合,x+n*2表示被x吃的动物所在的集合

    对于每一句话,若存在动物的编号大于n,显然这句话是假的

    我们先讨论集合的合并

    若x和y是同类,那么吃x的动物和吃y的动物在同一个集合,被x吃的动物和被y吃的动物在同一个集合;即将x和y所在集合合并,将x+n和y+n所在集合合并,将x+n*2和y+n*2所在集合合并

    若x吃y,则x和吃y的动物在同一个集合,y和被x吃的动物在同一个集合,即将x和y+n所在集合合并,将y和x+n*2所在集合合并。由题干描述的3种动物的捕食关系可知,还存在一个和x,y都不属于同一个集合的z,满足y吃z且z吃x。那么z所在集合应和y+n*2所在集合合并,且和x+n所在集合合并,我们可以把y+n*2和x+n所在集合合并即表示z所在集合。

    接下来我们讨论判断一句话的真假

    若是第一种说法,若这句话为真,则在已知的关系中必不存在x吃y,或y吃x,或x吃z,z吃y,或y吃z,z吃x,否则这句话为假。

    若是第二种说法,若这句话为真,则已知关系中必不存在x和y属于同一类,并且吃x的动物和吃y的动物不属于同一类,被x吃的动物和被y吃的动物不属于同一类(因为任意两个动物如果不是同类则只存在两种关系,即直接的吃与被吃,所以若吃两个动物的动物属于同一类,则这两个动物必属于同一类,被两个动物吃的动物亦然),否则这句话为假

     1 #include <cstdio>
     2 int n,m,f[150005],ans;
     3 int find(int x)
     4 {
     5     if (f[x]==x) return x;
     6     return f[x]=find(f[x]);
     7 }
     8 int main()
     9 {
    10     int i,j,p,x,y,fx,fy,fx1,fy1,fx2,fy2;
    11     //  x+n    捕食者 
    12     //  x+n*2  被捕食者 
    13     scanf("%d%d",&n,&m);
    14     for (i=1;i<=n*3;i++)
    15       f[i]=i;    
    16     while (m--)
    17     {
    18         scanf("%d%d%d",&p,&x,&y);
    19         if (x>n || y>n)
    20         {
    21             ans++;
    22             continue;
    23         }
    24         fx=find(x);  fy=find(y);
    25         fx1=find(x+n);  fy1=find(y+n);
    26         fx2=find(x+n*2);  fy2=find(y+n*2);
    27         if (p==1)
    28         {
    29             if (fx1==fy || fx2==fy || fx1==fy2 || fx2==fy1)
    30             {
    31                 ans++;
    32                 continue;
    33             }
    34             f[fx]=fy;  f[fx1]=fy1;  f[fx2]=fy2;
    35         }
    36         else
    37         {
    38             if (fx1==fy1 || fx1==fy || fx2==fy1)
    39             {
    40                 ans++;
    41                 continue;
    42             }
    43             f[fx]=fy1;  f[fx1]=fy2;  f[fx2]=fy;
    44         }
    45     }
    46     printf("%d",ans);
    47     return 0;
    48 }
  • 相关阅读:
    Linux 下的类似Windows下Everything的搜索工具
    windows和linux环境下制作U盘启动盘
    程序调试手段之gdb, vxworks shell
    LeetCode 1021. Remove Outermost Parentheses (删除最外层的括号)
    LeetCode 1047. Remove All Adjacent Duplicates In String (删除字符串中的所有相邻重复项)
    LeetCode 844. Backspace String Compare (比较含退格的字符串)
    LeetCode 860. Lemonade Change (柠檬水找零)
    LeetCode 1221. Split a String in Balanced Strings (分割平衡字符串)
    LeetCode 1046. Last Stone Weight (最后一块石头的重量 )
    LeetCode 746. Min Cost Climbing Stairs (使用最小花费爬楼梯)
  • 原文地址:https://www.cnblogs.com/rabbit1103/p/13888661.html
Copyright © 2011-2022 走看看