poj1182 食物链(经典关系并查集)
2016-05-22 20:41
295 查看
http://poj.org/problem?id=1182
题意:给你n个生物k个操作,生物之间有吃、被吃、同类三种关系,1,x,y代表x和y是同类,2,x,y代表x吃y,求假话数量。
思路:并查集高级应用,直接上大牛博客。刚开始看了几个说的不怎么明白的博客被误导了,现在把思路都理清吧。
p[x]代表x的父亲节点,r[x]代表x与p[x]的关系,x、y所在集合的代表元素rx、ry。
由于只有三种关系,所以我们命r[x]=0代表p[x]与x同类,r[x]=1代表p[x]吃x,r[x]=2代表x吃p[x]。而因为题中给出的操作d=1为同类,d=2为正向吃,正好与这里匹配,所以这里的数字代表权值,偏移量为1,途中的权值一般也就是d-1了。
Find操作:这是一个重点,找x所在集合的根节点(代表元素)。上述大牛博客中给出了推导思想,这里我感觉说的没人家好,仅仅记录下自己一些额外的理解。首先公式,r[ x ] = ( r[ x ] + r[ tmp ] )%3。这个公式有些地方说是找规律,事实上数学推导也行,不过没找规律快捷,这里有找规律的过程博客2。针对这个式子,他是根据爷爷父亲和父亲儿子的关系推导出爷爷孙子的关系,这里刚开始我没有理解。后来想想,这里递归查询根节点时,是一步一步往深递归,找到的根节点即为爷爷,返回上一层后pre[x]即为父亲,这里直接求出的爷孙关系r[x]就是当前递归层经历节点和根节点的关系啊!然后退回,中间传递根节点值,退回的节点再次成为了根节点的孙子。话句话说,这相当于从根开始,由深到浅往下拆树啊!!这思想精辟啊,理解了这点和公式,就不难了。
Union操作:将两个根节点不相同的根节点合并。思想刚开始的博客说清了,就是向量转移,根节点一变那关系也随之改变,只需改变根节点的关系即可。表达式:r[ rx ] = (3 - r[ x ] + d + r[ y ])%3。根据下图理解:(注意这里d改成d-1)
判断是否为假话,除了两种不需要通过并查集判断的情况外,都要检查他们的偏移量才可确定真假。而需要检查真假的肯定都在一个集合内了,所以不需要Union操作。这样的话只剩推导出公式,检验是否相等即可,公式性质和上图一样。(r[ x ] + 3 - r[ y ])%3 != d-1,即为假。
题意:给你n个生物k个操作,生物之间有吃、被吃、同类三种关系,1,x,y代表x和y是同类,2,x,y代表x吃y,求假话数量。
思路:并查集高级应用,直接上大牛博客。刚开始看了几个说的不怎么明白的博客被误导了,现在把思路都理清吧。
p[x]代表x的父亲节点,r[x]代表x与p[x]的关系,x、y所在集合的代表元素rx、ry。
由于只有三种关系,所以我们命r[x]=0代表p[x]与x同类,r[x]=1代表p[x]吃x,r[x]=2代表x吃p[x]。而因为题中给出的操作d=1为同类,d=2为正向吃,正好与这里匹配,所以这里的数字代表权值,偏移量为1,途中的权值一般也就是d-1了。
Find操作:这是一个重点,找x所在集合的根节点(代表元素)。上述大牛博客中给出了推导思想,这里我感觉说的没人家好,仅仅记录下自己一些额外的理解。首先公式,r[ x ] = ( r[ x ] + r[ tmp ] )%3。这个公式有些地方说是找规律,事实上数学推导也行,不过没找规律快捷,这里有找规律的过程博客2。针对这个式子,他是根据爷爷父亲和父亲儿子的关系推导出爷爷孙子的关系,这里刚开始我没有理解。后来想想,这里递归查询根节点时,是一步一步往深递归,找到的根节点即为爷爷,返回上一层后pre[x]即为父亲,这里直接求出的爷孙关系r[x]就是当前递归层经历节点和根节点的关系啊!然后退回,中间传递根节点值,退回的节点再次成为了根节点的孙子。话句话说,这相当于从根开始,由深到浅往下拆树啊!!这思想精辟啊,理解了这点和公式,就不难了。
Union操作:将两个根节点不相同的根节点合并。思想刚开始的博客说清了,就是向量转移,根节点一变那关系也随之改变,只需改变根节点的关系即可。表达式:r[ rx ] = (3 - r[ x ] + d + r[ y ])%3。根据下图理解:(注意这里d改成d-1)
判断是否为假话,除了两种不需要通过并查集判断的情况外,都要检查他们的偏移量才可确定真假。而需要检查真假的肯定都在一个集合内了,所以不需要Union操作。这样的话只剩推导出公式,检验是否相等即可,公式性质和上图一样。(r[ x ] + 3 - r[ y ])%3 != d-1,即为假。
#include <stdio.h> #include <algorithm> #include <stdlib.h> #include <string.h> #include <iostream> using namespace std; typedef long long LL; const int N = 100010; const int INF = 0x3f3f3f3f; int pre , sum, r ; int Find(int x) { if(x == pre[x]) return x; int tmp = pre[x]; pre[x] = Find(pre[x]); r[x] = (r[x]+r[tmp])%3; return pre[x]; } void Union(int x, int y, int d) { int rx = Find(x); int ry = Find(y); pre[rx] = ry; r[rx] = (3-r[x]+d-1+r[y])%3; } int main() { // freopen("in.txt", "r", stdin); int n, k, d, x, y; sum = 0;//假话数 scanf("%d%d", &n, &k); for(int i = 1; i <= n; i++) { pre[i] = i; r[i] = 0; } while(k--) { scanf("%d%d%d", &d, &x, &y); if(x > n || y > n) { sum++; continue; } if(d == 2 && x == y) { sum++; continue; } int rx = Find(x); int ry = Find(y); if(rx == ry) { if((r[x]+3-r[y])%3 != d-1) sum++; } else { Union(x, y, d); } } printf("%d\n", sum); return 0; }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题
- 2632 Crashing Robots的解决方法
- 1573 Robot Motion (简单题)