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

    【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 句话,输出假话的总数。

    解法

    1. 我们开三个并查集,分别表示这个动物 本身 食物 天敌,然后每次合并时,判断一下是否违法,并将对应的关系合并,就可以统计出假话的个数了。
    2. 我们利用权值并查集,用 $ kind[ i ] $表示 i 与他的父亲的关系。
      0 表示他与他的父亲是同类。
      1 表示他被他的父亲吃。
      2 表示他吃他的父亲。
      然后我们要获取父亲与他的关系,就用 $ ( 3 - kind[ i ] ) $就行了。更新关系就用 $ kind[i] = (kind[fa]+kind[i]) mod 3 $。

    代码

    第一类

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cctype>
    #define INF 2139062143
    #define MAX 0x7ffffffffffffff
    #define del(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    template<typename T>
    inline void read(T&x)
    {
        x=0;T k=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
    }
    const int maxn=(5e4+10)*3;
    int fa[maxn];
    int _find(int x) {
    	return fa[x]==x ? x : fa[x]=_find(fa[x]);
    } 
    void uni(int x,int y) {
    	int f1=_find(x),f2=_find(y);
    	if(f1!=f2) fa[f2]=f1;
    }
    
    int n,k;
    int main()
    {
    	read(n),read(k);
    	for(int i=1;i<=3*n;i++) fa[i]=i;// x本身 ,x+n食物 ,x+2*n天敌 
    	int tot=0;
    	for(int i=1;i<=k;i++) {
    		int c,x,y;
    		read(c),read(x),read(y);
    		if(x>n || y>n) {++tot;continue;}
    		if(c==1) {
    			if(_find(x+n)==_find(y) || _find(x+2*n)==_find(y)) ++tot;
    			else {
    				uni(x,y),uni(x+n,y+n),uni(x+2*n,y+2*n);
    			}
    		}
    		else {
    			if(x==y) {++tot;continue;}
    			if(_find(x)==_find(y) || _find(x+2*n)==_find(y)) ++tot;
    			else {
    				uni(x+n,y),uni(x,y+2*n),uni(x+2*n,y+n);
    			}
    		}
    	}
    	printf("%d",tot);
    	return 0;
    }
    

    第二类

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cctype>
    #define INF 2139062143
    #define MAX 0x7ffffffffffffff
    #define del(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    template<typename T>
    inline void read(T&x)
    {
        x=0;T k=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
    }
    const int maxn=5e4+10;
    int fa[maxn],kind[maxn];
    int _find(int x) {
    	int f=fa[x];
    	if(f!=x) {
    		fa[x]=_find(fa[x]);
    		kind[x]=(kind[x]+kind[f])%3;
    	}
    	return fa[x];
    } 
    int n,k;
    int main()
    {
    	read(n),read(k);
    	for(int i=1;i<=n;i++) fa[i]=i;
    	int tot=0;
    	for(int i=1;i<=k;i++) {
    		int c,x,y;
    		read(c),read(x),read(y);
    		if(x>n || y>n || (c==2&&x==y)) {++tot;continue;}
    		if(c==1) {
    			int f1=_find(x),f2=_find(y);
    			if(f1==f2) {if(kind[x]!=kind[y]) ++tot;}
    			else fa[f2]=f1,kind[f2]=(3-kind[y]+kind[x])%3;
    		}
    		else {
    			int f1=_find(x),f2=_find(y);
    			if(f1==f2) {if((kind[x]-kind[y]+3)%3!=2) ++tot;}
    			else fa[f2]=f1,kind[f2]=(4-kind[y]+kind[x])%3;
    		}
    	}
    	printf("%d",tot);
    	return 0;
    }
    
  • 相关阅读:
    PyCharm常用快捷键
    在PyCharm中打开文件的位置
    使用Socket下载图片
    Python散列类型和运算符
    Python格式化输出和深浅复制
    爬虫的概念和会话
    Python数值类型和序列类型
    HTTP与HTTPS
    PyCharm彻底删除项目
    PyCharm永久激活
  • 原文地址:https://www.cnblogs.com/mrasd/p/9550153.html
Copyright © 2011-2022 走看看