食物链(白书)(带权并查集)

标签: bing cha ji
7人阅读 评论(0) 收藏 举报
分类:
动物王国中有三类动物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

这道题考察了带权并查集,是目前见过的并查集中的最高层次,给我的启发很大,对照着代码对应着理解快点。

但是最根本的思想还是并查集,但是多了个带权的。

然后用动物之间的相对关系来确定并查集

0-这个节点与父节点是同类

1-这个节点被他的父节点吃

2-这个节点吃它的父节点

struct animal{
	int parent;
	int num;
	int relation;	
};

这个数字定下来是有依据的,因为跟据(d-1)就可以看出来了

然后就是开始创建并查集了,当然最开始都得初始化

void init_animal(int n)
{
	for(int i=1;i<=n;i++){
		ani[i].num=i;
		ani[i].parent=i;
		ani[i].relation=same;
	}	
}

接着我们开始找父节点,找的过程,就是我们路径压缩的过程,为何还要使用指针呢?那必须了,因为不仅要返回一个父节点的序号,更是要使深度变为2,得改变现在这个结点的父节点与关系,这样就得考虑此节点的父节点与此节点与爷爷结点的关系如何算的了?node->relation=(ani[node->parent].relation+node->relation)%3 为何是这样的了呢?穷举下


这个得亲自推导推导就透彻了,还有一个为什么要路径压缩呢?因为如果两个并查集并到一起,那么这个大的并查集是不是深度就超过3了,那么就与推导出现了问题,因为最后都要使其深度为2,这也是刚开始wa的原因,一直在想为什么要路径压缩,不仅仅是为了下次找父节点更快,更是为了答案。

int findparent(animal *node)
{
	int tmp;
	if(node->parent==node->num){
		return node->parent;
	}
	tmp=node->parent;
	node->parent=findparent(&ani[node->parent]);
	node->relation=(ani[tmp].relation+node->relation)%3;
	return node->parent;
}

最后我们得知道的就是最最关键的怎么合并两个不同的并查集

比如我们假设集合A中有{1-6},B中又{7-10},C中有{11-16}

比如现在给了2 13 2这句真话,意思是13吃2呢,并且是真的,那么如何将这种情况合并呢?

就得先找到2的父节点,假设如下图所示为1,并且与2为同类,13也如此。

那么就ani[1].parent=11,并查集中的靠左原则,然后最最重要的来了,ani[1].relation=((3-ani[2].relation)+(d-1)+ani[13].relation),验证下(3+1+0)%3=1,也就是说11吃1,这句话肯定是真的啦!这也是跟据穷举算出来的。

void merge(int x,int y,int a,int b,int d)
{
	ani[b].parent=a;
	ani[b].relation=((3-ani[y].relation)+(d-1)+ani[x].relation)%3;
	cout<<ani[b].relation<<endl;
}


然后就是找到的父节点相同的话,就开始判断。

switch(d){
    case 1:
	if(ani[x].relation!=ani[y].relation){//是否同类
	    ans++;
	}
	break;
    case 2:
	if(((ani[y].relation+3-ani[x].relation)%3)!=1){//是否符合被吃的关系,跟据路径压缩的逆关系推出来
	    ans++;
	}
	break;
}

然后就完美的解决了这道题.看下完整的代码

//带权并查集 
#include<iostream>
#include<cstdio> 

using namespace std;

const int maxn=5e4+10;
const int same=0;
const int enemy=1;
const int food=2;

struct animal{
	int parent;
	int num;
	int relation;	
};

animal ani[maxn];

long ans;

int findparent(animal *node)
{
	int tmp;
	if(node->parent==node->num){
		return node->parent;
	}
	tmp=node->parent;
	node->parent=findparent(&ani[node->parent]);
	node->relation=(ani[tmp].relation+node->relation)%3;
	return node->parent;
}

void merge(int x,int y,int a,int b,int d)
{
	ani[b].parent=a;
	ani[b].relation=((3-ani[y].relation)+(d-1)+ani[x].relation);
}

void init_animal(int n)
{
	for(int i=1;i<=n;i++){
		ani[i].num=i;
		ani[i].parent=i;
		ani[i].relation=same;
	}	
}

int main()
{
	int n,k;
	int d,x,y;
	scanf("%d%d",&n,&k);
	init_animal(n);
	for(int i=0;i<k;i++){
		scanf("%d%d%d",&d,&x,&y);
		if(x>n||y>n){
			ans++;
		}else{
			if(d==2&&x==y){
				ans++;
			}else{
				int a=findparent(&ani[x]);
				int b=findparent(&ani[y]);
				if(a!=b){
					merge(x,y,a,b,d);
				}else{
					switch(d){
						case 1:
							if(ani[x].relation!=ani[y].relation){
								ans++;
							}
							break;
						case 2:
							if(((ani[y].relation+3-ani[x].relation)%3)!=1){
								ans++;
							}
							break;
					}
				}
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
查看评论

POJ1182 - 食物链(带权并查集)

题目链接:http://poj.org/problem?id=1182题目大意:动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-...
  • ACM_Fish
  • ACM_Fish
  • 2017-05-13 10:25:23
  • 975

poj 1182 (带权并查集)

Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不...
  • Balloons2012
  • Balloons2012
  • 2012-08-15 22:52:05
  • 7430

POJ1182 食物链 带权并查集

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有...
  • FrankAx
  • FrankAx
  • 2017-08-02 19:02:18
  • 152

poj 食物链

  • 2013年11月18日 15:37
  • 1KB
  • 下载

食物链 带权并查集

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有人...
  • qq_33132383
  • qq_33132383
  • 2017-04-10 16:33:10
  • 79

食物链(带权并查集)

Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。  现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它...
  • lianweicheng88
  • lianweicheng88
  • 2015-07-31 16:45:43
  • 169

食物链 带权并查集

食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 75476 Accepte...
  • qq_37533501
  • qq_37533501
  • 2017-08-03 16:25:49
  • 73

食物链(带权并查集)

题目大意: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪...
  • ToBeYours
  • ToBeYours
  • 2018-01-25 14:24:30
  • 48

并查集与带权并查集(转)

转自Chris_zzj的博客! 并查集 并查集是一个很高效算法,理解起来也很简单,写起来更简单。 ①fat[i] = i; ②找到一个点的祖先 ...
  • ACM77
  • ACM77
  • 2017-07-19 10:36:13
  • 331

poj 1182 食物链(经典!种类并查集)

链接: http://poj.org/problem?id=1182 原题: Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形...
  • shuangde800
  • shuangde800
  • 2012-09-24 00:10:11
  • 7504
    个人资料
    持之以恒
    等级:
    访问量: 6350
    积分: 2760
    排名: 10万+
    文章存档
    最新评论