POJ 1182 食物链
来源:互联网 发布:武汉矩阵选房系统 编辑:程序博客网 时间:2024/06/05 00:08
这题用并查集来写,且树的层数不超过2,3层最多只持续一个循环就会变成2层,因为只有三种动物,两两之间的关系只需要2层树就可以表示清楚了,那么现在当树有三层时怎么变成2层树呢?
先假设0,1,2分别为该结点与父结点表示的关系,0表示同类,1表示该结点被父结点吃,2表示该结点吃父结点。
这个表示方法是有原因的,目的是为了下面方便推公式,首先题目给出d表示关系,d==1表示同类,d==2表示y被x吃,那么的d-1==0,刚好表示同类,d-1==1刚好表示该结点被父结点吃(当d==2时,把x作为父结点)。
那么怎么算第三层与第一层结点的关系,并且把第三层上的结点变成第二层呢?
首先给出公式:(re[a]+re[pa[a]])%3==子结点对爷爷结点的关系;
a表示子结点,pa[a]表示父亲结点,这个公式是通过穷举法得出的,其中re数组表示该结点与父结点的关系,求出这个关系那么就可以把子结点挂到爷爷结点下面,就是把第三层结点放到了第二层上。
公式是这样推的 <span style="white-space:pre"></span> 父亲 儿子 儿子对爷爷的关系
- 0 0 (i + j)%3 = 0
- 0 1 (i + j)%3 = 1
- 0 2 (i + j)%3 = 2
- 1 0 (i + j)%3 = 1
- 1 1 (i + j)%3 = 2
- 1 2 (i + j)%3 = 0
- 2 0 (i + j)%3 = 2
- 2 1 (i + j)%3 = 0
- 2 2 (i + j)%3 = 1
现在单个结点并到一个集合中的方法已经有了,那就要考虑集合并集合了,如果题目给出x,y的关系,并且x与y在之前并没有关系且x与y所属不同的集合,那么就不能直接把y的根结点并到x的根结点上,因为你并不知道这两个根结点之间的关系,那么现在的首要问题就是要求出根结点a(x),b(y)之间的关系。
方法如下:我们假设把y结点接到x结点的下方,再把b结点(也就是y的根结点)接到y的下方,那么根据(re[y]+re[b])%3来求出b结点与x结点的关系,在用(re[x]+re[b])%3来求出b结点与a结点的关系(此时的re[b]已经被更新过了),那样的话b结点就可以接到a结点的下方。
那么问题又来了,如何求出最开始的re[b]呢,也就是b结点与y的关系。
这里用的也是穷举法,得出勇士父结点与子结点的关系就是:re[父对子]=(3-re[子对父])%3。
这个很快就可以穷举出,这里就不穷举,那么通过这个公式就可以把上面求b与a关系的两个式子整理为一个式子,(d-1+3-re[y]+re[x])%3==b结点对a结点的关系
其中d-1==re[y]这个式子在一开始说三个标志数取法的时候就已经给出,3-re[y]则是b对y的关系。
这样就可以把两个集合并起来了。
然后是判断是否说的是假话,如果a,b结点不同,那这是之前没有表明过a与b的关系,为真话,那么就把它们所属的集合并起来。
如果a与b相同,如果d==1那么只要判断re[x]是否等于re[y]就可以了,因为是二层树,所以相等为真话,不相等为假话。
如果d==2,那么需要需要把根结点当做x的子结点,然后根据公式(re[y]+3-re[x])%3是否为1即可,如果为1,则真话,不为1则为假话。
思路来源:http://blog.csdn.net/c0de4fun/article/details/7318642/
代码:
//// main.cpp// Richard//// Created by 邵金杰 on 16/7/23.// Copyright © 2016年 邵金杰. All rights reserved.//#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn=50000+100;int pa[maxn],re[maxn];int cnt=0;int getroot(int a){ if(pa[a]==a) return a; int t=getroot(pa[a]); re[a]=(re[pa[a]]+re[a])%3; pa[a]=t; return pa[a];}void Union(int x,int y,int a,int b,int d){ pa[b]=a; re[b]=(d-1+3-re[y]+re[x])%3;}int main(){ int n,k; int d,x,y; scanf("%d%d",&n,&k); for(int i=0;i<=n;i++){ pa[i]=i;re[i]=0; } for(int i=0;i<k;i++) { scanf("%d%d%d",&d,&x,&y); if(x>n||y>n) {cnt++;continue;} if(d==2&&x==y) {cnt++;continue;} int a=getroot(x); int b=getroot(y); if(a!=b) Union(x,y,a,b,d); else{ if(d==1&&re[x]!=re[y]) cnt++; if(d==2&&(re[y]+3-re[x])%3!=1) cnt++; } } cout<<cnt<<endl;}
- poj 1182 食物链
- poj 1182 食物链
- poj 1182 食物链(转)
- poj 1182 食物链
- poj 1182 食物链
- poj 1182 食物链
- POJ-1182 食物链
- POJ 1182 食物链
- poj 1182食物链
- POJ 1182 食物链
- POJ 1182 食物链
- poj 1182 食物链
- POJ 1182 食物链
- POJ 1182 食物链
- poj 1182 食物链
- POJ 1182 - 食物链
- poj 1182 食物链
- poj 1182 食物链
- 8大排序
- hibernate一对多双向关联-mysql
- C++基础:钻石继承与虚基类
- JAVA存储数据的5个地方
- Codeforces 468C Hack it!
- POJ 1182 食物链
- 自学Java第一篇
- JAVA面向对象-----extends关键字
- kernel 启动流程
- java变量初始化
- markdown使用技巧
- 自己看的一点mongodb资料网站。觉得不错
- Intellij IDEA 14.x 中的Facets和Artifacts的区别
- 自动选择一个输入时间