POJ-1182-食物链- 经典并查集应用
来源:互联网 发布:阿里云访问美国ip慢 编辑:程序博客网 时间:2024/05/29 11:09
Description
现有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),输出假话的总数。
用到 并查集的fa[]数组,指的是 当前点x的祖先,
而用一个path【】数组,表示 当前点x与祖先的距离, 如果距离%3==0,与祖先为同类,距离%3==1表示 祖先吃x,距离%3==2表示x吃祖先,
之所以模三 是因为 关系就三种,且 刚好是 连续、构成一个环的关系。 因为关系只有三种 所以 大于等于三的距离,与 其自身对三的取模值 是等价的
【所以一个fa根节点的集合内,他们之间所有节点的联系 是 x 与祖先的 关系】
首先肯定判断是否有 自己吃自己的情况,其次 x、y大于n的情况.
并且 如果 给出的x与y 根本不在一个集合内,那么无论怎么说,都是合法的(因为是第一次出现)
如果d==1,表示 认为x与y是同类
我们找到他们的根,fx,fy。
如果fx==fy; 那么他们是同一祖先,判断他们是否同类==》 判断他们与祖先的关系是否同样==》 他们与祖先的距离是否一样,即path[x]==path[y];
如果fx!=fy; 那么他们不是同祖先, 新给的关系肯定是合法的,我们只需要维护,也就是 把两个集合合并 (本代码以fy为新根), 并更新fx集合中所有点到新根fy的距离,更新的过程如下:
首先 原来 y-->fy的距离为f[y] , x---->fx的距离为f[x],
合并之后的关系是 x---->fx------>fy<--------y;
因为x与y同类,所以distance(x,y)=0,
所以他们的【距离关系】可以近似看作这样的情况 y(x)----->fx---->fy;
所以得出 path[fx]=path[y]-path[x]; 前者指y到fy的距离,后者指,x到fx的距离;
如果d==2,表示x吃y
先找根
如果fx==y; 那么他们是同一祖先,判断是否满足x吃y ==》 判断他们与祖先关系只差是否为2 ,即((path[x]-path[y]-2)+3)%3==0 ;取模是怕出现负数 至于为什么用 差2 而不是差1 ,与我们每次选fy为根节点有关,见代码注释;
如果fx!=fy,则需要 维护,也就是合并集合, 并更新fx集合中所有点到新根fy的距离,更新的过程同上:
首先 原来 y-->fy的距离为f[y] , x---->fx的距离为f[x],
合并之后的关系是 x---->fx------>fy<--------y;
因为x吃y,所以distance(x,y)=2, //ps:如果一直默认以fx为新根,dis会是1,想想为什么,和上面的判断是同一个道理
所以他们的【距离关系】可以近似看作这样的情况 x---->y----->fx---->fy;
所以得出 path[fx]=path[y]-path[x]+2; 前者指y到fy的距离,后者指,x到fx的距离;
所有path的计算都要注意如果得到负数或者大于等于3的结果要取模,本代码的实现放在里find函数中
#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map>#include <set>#include <vector>using namespace std;int n;int path[50005];int fa[50005];int find(int x){if (fa[x]==x){path[x]=(path[x]+3)%3;return fa[x];}else { int fx=find(fa[x]);path[x]=(path[fa[x]]+path[x]+3)%3;// 更新为:自己到原先fa[x]的路径 + 新的fa[x]到根节点的路径return fa[x]=fx; }}int main(){ int n,k;cin>>n>>k;int op,x,y;int i ;for (i=1;i<=n;i++)fa[i]=i,path[i]=0;int cun=0;for (i=1;i<=k;i++){scanf("%d%d%d",&op,&x,&y);if (x>n||y>n) {cun++;continue;}if (x==y&&op==2) {cun++;continue;}int fx=find(x);int fy=find(y);//找到各自的根if (op==1)//同类判断{if (fx==fy)//如果同根{if (path[x]!=path[y]) //那么他们与祖先的距离应该相同,cun++;continue;}else if (fx!=fy)//如果不同类则合并{fa[fx]=fy;//由fx指向fy;path[fx]=path[y]-path[x]; //由向量关系得 path[fx]=path[y]+dis(x-y)-path[x],其中dis(x-y)=0; //注意可能为负数,因此在find函数中加了+3%3操作,也可直接在此+3%3}}else{//因为当x吃y,且要合并他们时,我们默认把fy作为新根,所以描述x吃y的关系用的是 path[x]=path[y]+2;//如果用fx为根,那么应该用path[x]=path[y]+1;if (fx==fy)//由于上一行的关系,所以此处判断是否符合x吃y的关系式 是path[x]-path[y]!=2 而不是差1{if ((path[x]-path[y]+3)%3!=2) //这比较必定要+3%3cun++;}else{fa[fx]=fy;path[fx]=path[y]+2-path[x]; //注意可能为负数,因此在find函数中加了+3%3操作,也可直接在此+3%3} }}printf("%d\n",cun);return 0;}
- 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食物链(经典的并查集)
- c++ int,float等转string
- mybatis删除,修改,新增返回操作
- ACP敏捷项目管理微课-敏捷管理流程及框架(丁仿)
- Spring注解入门
- keystone中的domain
- POJ-1182-食物链- 经典并查集应用
- Java语言中反射动态代理接口的解释与演示
- UITableView
- Cocos2d-x命令生成的工具导入到Eclipse中
- Java 静态代码块讲解
- Python Argparse模块的使用例子,往python脚本传参数
- jquery text val html区别
- table的代理方法 删除cell可编辑状态
- 关于图片加载性能优化总结