【题解 && 并查集】 食物链

题目传送门

题目描述:

动物王国中有三类动物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),输出假话的总数。


输入格式
第一行是两个整数N和K,以一个空格分隔。 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。

输出格式
只有一个整数,表示假话的数目。


分析:

这道题经过题意转化后其实就是一个比较复杂的关系处理。
因为这道题需要同时处理 同类 食物 天敌 之间的关系。

想到关系处理,我们可能会想到两种方式: 并查集
这道题用图不是不能做,不过显然比用并查集麻烦。
所以这道题就是一道并查集的题目。

  • 此时引入一下并查集 扩展域 的概念。
    其实就是多个并查集 共同处理关系

所以我们根据题意,发现可以定三个并查集,也就是将并查集的长度扩展到三倍长。
注:最好不要用多个并查集来存储关系,因为他们之间并没有共同点,对于关系的处理也就会出错(就是这么错过来的…………)

我们设:
f a [ i ] i fa[i]表示以i为编号的父亲
1 i   ( 1 &lt; = i &lt; = n ) 1、处理i的同类的关系 \ (1&lt;=i&lt;=n)
2 i   ( n + 1 &lt; = i &lt; = 2 n ) 2、处理i的天敌的关系\ (n+1&lt;=i&lt;=2*n)
3 i ( 2 n + 1 &lt; = i &lt; = 3 n ) 3、处理i的食物的关系 (2*n+1&lt;=i&lt;=3*n)

那么题目中说的假话也就是与之前话冲突的话,那么怎么样算与之前冲突的呢?
有四种情况:
1 1、同类吃同类
2 2、同类吃天敌
3 3、和天敌是同类
4 4、 和食物是同类

那么只要按照以上四中关系处理即可。


Code

/*
1、同类吃同类
2、同类吃天敌
3、和天敌是同类
4、 和食物是同类 

1-n 同类
n+1-2*n 天敌
2*n+1-3*n 食物
*/
#include<bits/stdc++.h>
using namespace std;
int fa[1000001];
int n,m;
int ans=0;
int getfa(int k){
    return k==fa[k]?k:fa[k]=getfa(fa[k]);
}
int main(){
	freopen("eat.in","r",stdin);
	freopen("eat.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n*3;i++) fa[i]=i;
    for (int i=1,x,y,z;i<=m;i++){
		scanf("%d %d %d",&z,&x,&y);
		if (x>n||y>n) {ans++;continue;}
		if (z==2&&x==y) {ans++;continue;}
		if (z==1){
			if (getfa(x+n)==getfa(y)&&x!=y) {ans++;continue;}//3
			if (getfa(x+2*n)==getfa(y)&&x!=y) {ans++;continue;}//4
			fa[getfa(x)]=getfa(y);
			fa[getfa(x+n)]=getfa(y+n);
			fa[getfa(x+2*n)]=getfa(y+2*n);
		}
		if (z==2){
			if (getfa(x)==getfa(y)) {ans++;continue;}//1
			if (getfa(x+n)==getfa(y)) {ans++;continue;}//2
			fa[getfa(x)]=getfa(y+n);
			fa[getfa(x+n)]=getfa(y+2*n);
			fa[getfa(x+2*n)]=getfa(y);
		}
	}
	printf("%d",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huang_ke_hai/article/details/88864128