poj 1182 食物链 && nyoj 207(种类并查集)

食物链

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 52414   Accepted: 15346

Description

动物王国中有三类动物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

题意为:有A、B、C三种动物。A吃B,B吃C,C吃A,并给出一些条件,推断为你提供信息的人说了多少句假话。

并查集。通经常使用来检查两个元素是否在同一集合中,或者是将两个不同的集合为一个集合。

至于这道题。有神人曰。利用并查集,同一时候对每一个节点保持其到根结点的相对类别偏移量,定义为:

0——同类;

1——食物;

2——天敌。

一个非常具体的解题报告,看得我五体投地:点击打开链接

这里他讲的异常具体,哪一点都有讲到,,当中60行到180行就有下边凝视的公式的解析

好厉害。,2015,7,27

#include<stdio.h>
#define M 50005
int x[M],re[M];
void init()
{
	for(int i=0;i<M;i++){
		x[i]=i; re[i]=0;
	}
}
int find(int k)
{
	int temp=x[k];
	if(x[k]==k) return k;
	x[k]=find(x[k]);
	re[k]=(re[k]+re[temp])%3;//( 儿子的关系 + 父亲的关系 ) % 3 = 儿子对爷爷的关系
	return x[k];
}
void merge(int a,int b,int fa,int fb,int d)
{
	x[fa]=fb;
	re[fa]=(re[b]-re[a]+d+3)%3;//d是a与b的关系,(3-re[a])是a为根节点时,他父亲的关系,(re[b]-re[a]+d+3)%3就是a的根节点与他的父亲就是b的根节点的关系 
}
int main()
{
	int n,m,a,b,d,fa,fb,count=0;
	scanf("%d%d",&n,&m);
	init();
	while(m--){
		scanf("%d%d%d",&d,&a,&b);
		if( a>n || b>n || (a==b && d==2) ){
			count++;
			continue;
		}
		fa=find(a);
		fb=find(b);
		if(fa==fb&&(re[a]-re[b]+3)%3!=d-1)//3-re[b]就得到了根节点和b的关系,re[a]+3-re[b]就是a关于b的关系 
			count++;
		else
			merge(a,b,fa,fb,d-1);
	}
	printf("%d\n",count);
	return 0;
}

还有第二种比較巧妙的简单的方法:

对于每仅仅动物i创建3个元素i-A, i-B, i-C, 并用这3*N个元素建立并查集。这个并查集维护例如以下信息:

① i-x 表示 “i属于种类x”。

②并查集里的每个组表示组内全部元素代表的情况都同一时候发生或不发生。

比如,假设i-A和j-B在同一个组里,就表示假设i属于种类A那么j一定属于种类B,假设j属于种类B那么i一定属于种类A。

因此,对于每一条信息。仅仅须要依照以下进行操作就能够了。

1)第一种。x和y属于同一种类———合并x-A和y-A、x-B和y-B、x-C和y-C。

2)另外一种,x吃y—————————合并x-A和y-B、x-B和y-C、x-C和y-A。

只是在合并之前须要先推断合并是否会产生矛盾。比如在第一种信息的情况下,

须要检查比方x-A和y-B或者y-C是否在同一组等信息。

(一開始我一直不明确。对于两种信息都是合并,

那么以后怎么分清究竟是同类还是捕食关系呢,或者说怎样推断是否会产生矛盾呢?

后来发现,它利用3*N的数组分3段1~N,N~2N,2N~3N分别当做是A、B、C三个种类的集合,

把全部可能符合的情况都会导入进去。尽管对于两种信息的操作都是合并。

但合并的内容是不一样的,这样就能够在合并之前推断其是否以还有一种信息合并过或者符合还有一种信息。能够自己举例来理解一下)

#include<stdio.h>
#define M 50005*3
int x[M];
void init()
{
	for(int i=0;i<M;++i){
		x[i]=i;
	}
}
int find(int k)
{
	if(x[k]==k) return k;
	x[k]=find(x[k]);
	return x[k];
}
void merge(int a,int b)
{
	int fa=find(a); int fb=find(b);
	if(fa!=fb) x[fa]=fb;
}
bool same(int a,int b)
{
	return find(a)==find(b);
}
int main()
{
	int n,m,a,b,c,count=0;
	scanf("%d%d",&n,&m);
	init();
	while(m--){
		scanf("%d%d%d",&c,&a,&b);
		//元素a。a+N,a+2*N分别代表a-A。a-B,a-C
		if(a>n || b>n ||(a==b && c==2)) {
			count++;
			continue;
		}
		if(c==1){
			if(same(a,b+n) || same(a,b+2*n))
				count++;
		//对于第一种信息是不能出现捕食与被捕食关系的
			else{
				merge(a,b);
				merge(a+n,b+n);
				merge(a+2*n,b+2*n);
			}
		}
		else{
			if(same(a,b) || same(a,b+2*n)) count++;
			//不能出现捕食同类和反捕食的情况
			else{
				merge(a,b+n);
				merge(a+n,b+2*n);
				merge(a+2*n,b);
			}
		}
	}
	printf("%d\n",count);
	return 0;
 } 
时间: 2024-08-28 01:29:38

poj 1182 食物链 &amp;&amp; nyoj 207(种类并查集)的相关文章

poj 2492 a bug&#39;s life 简单种类并查集

题意大致为找同性恋的虫子.... 这个比食物链要简单些.思路完全一致,利用取余操作实现关系之间的递推. 个人感觉利用向量,模和投影可能可以实现具有更加复杂关系的并查集. 1 #include<cstdio> 2 using namespace std; 3 const int MAXN=50010; 4 int fa[MAXN]; 5 int rel[MAXN]; // 0代表同类,1代表吃fa[i],2代表被吃 6 void _set(int n) 7 { 8 for(int i=1;i&l

【POJ】2492 A bug&#39;s life ——种类并查集

A Bug's Life Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 28211   Accepted: 9177 Description Background Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders

种类并查集,Poj(1703)

题目链接:http://poj.org/problem?id=1703 第一次做种类并查集,有的地方还不是很清楚,想了一上午,有点明白了,这里记录一下. 这里我参考的红黑联盟的题解. 关键:种类并查集与带权并查集实质上的差别并不大, 关键的区别就是种类并查集只是带权并查集再弄个%取余操作而已,然后余数就表示他属于哪个种类. rank数组表示节点和父节点的关系(也可以理解为他的种类). find中,找到x的父节点后,那么更新他与父节点的关系,rank[x] = (rank[x]+rank[fa])

POJ1703--Find them, Catch them(种类并查集)

Time Limit: 1000MSMemory Limit: 10000K Total Submissions: 32909Accepted: 10158 Description The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, t

带权并查集(含种类并查集)【经典模板】 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug&#39;s life(简单) ③hihoCoder 1515 : 分数调查

带权并查集: 增加一个 value 值,并且每次合并和查找的时候需要去维护这个 value 例题一 :POJ 1182 食物链(经典) 题目链接:https://vjudge.net/contest/339425#problem/E 带权并查集的解法 定义两个数组fa[ ]和rela[ ],fa用来判断集合关系,rela用来描述其与根节点的关系.因为关系满足传递性,所以可以推导出给出条件下的当前关系,在判断与之前已有关系是否矛盾. 本题的解法巧妙地利用了模运算,rela数组用0表示同类,1表示当

poj 1182 食物链(种类并查集 ‘初心者’)

题目链接:http://poj.org/problem?id=1182 借着这题可以好好理解一下种类并查集,这题比较简单但挺经典的. 题意就不解释了,中问题. 关于种类并查集结局方法也是挺多的 1扩增倍数. 就是有几种关系就建立几倍数组,具体方法在这里不详细说了,这种方法有弊端 比较复杂而且内存消耗比较大如果关系比较多就容易爆掉. 2向量的方法. 这种方法要详细解说一下.这个方法好处都有啥.......(自行脑补后面的话) 这个方法的优点占用内存比较小而且比较简洁.只要找到关系就行. 下面就用方

poj 1182食物链【种类并查集】

食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 49310   Accepted: 14382 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同

POJ 1182食物链 种类并查集的经典

题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/ 题意:给出动物之间的关系,有几种询问方式,问是真话还是假话. 定义三种偏移关系: x->y 偏移量0时 x和y同类 x->y 偏移量1时 x被y吃 x->y 偏移量2时 x吃y 定义 rela[x]=rx->x; 如x,y不在同一个集合中, 由rx->ry=rx->x + x->y + y->ry=(rx->x)+(x->y)-(ry->y)可得

poj 1182 食物链 (带关系的并查集)

  食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44835 Accepted: 13069 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类.