码迷,mamicode.com
首页 > 其他好文 > 详细

poj 1182 食物链

时间:2018-04-25 00:24:29      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:img   one   out   isp   nta   有趣的   init   两种   结果   

动物王国中有三类动物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
学习带权并查集。
代码:
技术分享图片
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#define Max 50005
using namespace std;
int n,k,f[Max],tag[Max],c;
///f记录双亲结点 tag记录与双亲结点关系 0表示同类 1表示吃该结点 2表示被该结点吃
///e.g. 1吃2 tag[1] = 0(初始和自己同类),tag[2] = 1;2吃3 tag[2] = 1,tag[3] = 1,getf之后 tag[3] = 2,因为3吃1;34同类 tag[3] = 2,tag[4] = 0,getf之后tag[4] = 2
///现在tag[1] = 0,tag[2] = 1,tag[3] = 2,tag[4] = 2
///此时判断 1吃2 (tag[2] - tag[1] + 3) % 3 = 1 满足;判断4吃2 (tag[2] - tag[4] + 3) % 3 = 2,结果是4被2吃
///观察如果两个点x,y是同一个双亲,列举xy和双亲的关系
///1.xy都被吃tag[x] = 1,tag[y] = 1,此时xy同类计算针对于x的tag‘[y]应该是 0 满足(tag[y] - tag[x] + 3) % 3 = 0
///2.x被吃 被y吃 tag[x] = 1,tag[y] = 2,y被x吃,tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 1 (两个交换类似)
///3.x同类 被y吃 tag[x] = 0,tag[y] = 2,y吃x,tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 2 (两个交换类似)
///4.x同类 y被吃 tag[x] = 0,tag[y] = 1,y被x吃, tag‘[y] = (tag[y] - tag[x] + 3) % 3 = 1 (两个交换类似)
///5.xy都同类显而易见
///6.被xy都吃,xy也是同类的
void init()
{
    for(int i = 1;i <= n;i ++)
    {
        f[i] = i;///初始双亲是自己
    }
}
int getf(int a)///寻根压缩
{
    if(f[a] != a)
    {
        int t = getf(f[a]);///如果直接让f[a] = 根 下一步就没意义了,tag[根] = 0
        tag[a] = (tag[a] + tag[f[a]]) % 3;///根据a和双亲的关系与双亲和根的关系 转化为a和根的关系(规律很容易发现)
        f[a] = t;
    }
    return f[a];
}
int mer(int d,int a,int b)///d = 0 同类 d = 1 a吃b
{
    int aa = getf(a);
    int bb = getf(b);
    if(aa == bb)///表示在同一条食物链中
    {
        if((tag[b] - tag[a] + 3) % 3 != d)return 0;
        return 1;
    }
    tag[bb] = (tag[a] - tag[b] + 3 + d) % 3;
    f[bb] = aa;
    return 1;
}
int main()
{
    int d,a,b;
    scanf("%d%d",&n,&k);
    init();
    for(int i = 0;i < k;i ++)
    {
        scanf("%d%d%d",&d,&a,&b);
        if(a > n || b > n || !mer(d - 1,a,b))c ++;///超过范围是假话 与原话不符或者与事实不符
    }
    printf("%d",c);
}
View Code

 

poj 1182 食物链

标签:img   one   out   isp   nta   有趣的   init   两种   结果   

原文地址:https://www.cnblogs.com/8023spz/p/8934365.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!