poj1182(食物链)
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 49320 | Accepted: 14385 |
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),输出假话的总数。
Input
以下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
建议:做此题之前先做 poj 2524 和 poj 1611。这两道题都是并查集的基础应用。
关键词:并查集 相对关系
思路:(用一个并查集就够了,同时对每个节点保持其到根结点的相对类别偏移量)
1.father[x]表示x的根结点。rank[x]表示father[x]与x的关系。rank[x] == 0 表示father[x]与x同类;1表示father[x]吃x;2表示x吃father[x]。
2.怎样划分一个集合呢?
注意,这里不是根据x与father[x]是否是同类来划分。而是根据“x与father[x]能否确定两者之间的关系”来划分,若能确定x与father[x]的关系,则它们同属一个集合。
3.怎样判断一句话是不是假话?
假设已读入 D , X , Y , 先利用find_set()函数得到X , Y 所在集合的代表元素 xf ,yf ,若它们在同一集合(即 xf == yf )则可以判断这句话的真伪( 据 2. ).
若 D == 1 而 rank[X] != rank[Y] 则此话为假。(D == 1 表示X与Y为同类,而从rank[X] != rank[Y]可以推出 X 与 Y 不同类。矛盾。)
若 D == 2 而 rank[X] == rank[Y] (X 与Y为同类)或者 rank[X] == ( rank[Y] + 1 ) % 3 (Y吃X )则此话为假。
4.上个问题中 r[X] == ( r[Y] + 1 ) % 3这个式子怎样推来?假设有Y吃X,那么r[X]和r[Y]的值是怎样的?
我们来列举一下: r[X] = 0 && r[Y] = 2
r[X] = 1 && r[Y] = 0
r[X] = 2 && r[Y] = 1
稍微观察一下就知道r[X] = ( r[Y] + 1 ) % 3;事实上,对于上个问题有更一般的判断方法:
若 ( r[Y] - r[X] + 3 ) % 3 != D - 1 ,则此话为假。(来自poj 1182中的Discuss )
5、注意事项:
A、我们用x--r-->y表示x和y之间的关系是r,比如x--1--y代表x吃y。现在,若已知x--r1-->y,y--r2-->z,如何求x--?-->z?,于是我们不难发现,x--(r1+r2)%3-->z。这个就是在Find_Set(int x)函数中用到的更新x与father[X]的关系
B、当D X Y时,则应合并X的根节点和Y的根节点,同时修改各自的rank。那么问题来了,合并了之后,被合并的根节点的kind值如何变化呢?
现有x和y,d为x和y的关系,xf和yf分别是x和y的根节点,于是我们有x--rank[x]-->xf,y--rank[y]-->yf,显然我们可以得到xf--(3-rank[x])-->x,yf--(3-rank[y])-->y。假如合并后x为新的树的根节点,那么原先fx树上的节点不需变化,yf树则需改变了,因为rank值为该节点和树根的关系。这里只改变rank(yf)即可,因为在进行find_set操作时可相应改变yf树的所有节点的kind值。于是问题变成了yf--?-->xf。我们不难发现yf--(3-rank[y])-->y--(3-d)-->x--rank[x]-->xf,根据前面的结论,我们有yf--(3-rank[y])-->y--(3-d)-->x--rank[x]-->xf。我们求解了xf和yf的关系了。
代码如下:
- #include <iostream>
- const int MAX=50005;
- int father[MAX];
- int rank[MAX];
- //初始化集合
- void Make_Sent(int x)
- {
- father[x]=x;
- rank[x]=0;
- }
- //查找x的集合,回溯时压缩路径,并修改x与father[x]的关系
- int Find_set(int x)
- {
- int t;
- if(x!=father[x])
- {
- t = father[x];
- father[x]= Find_set(father[x]);
- //更新x与father[X]的关系
- rank[x] = (rank[x]+rank[t])%3;
- }
- return father[x];
- }
- //合并x,y所在的集合
- void Union(int x,int y,int d)
- {
- int xf = Find_set(x);
- int yf = Find_set(y);
- //将集合xf合并到yf集合上
- father[xf] = yf;
- //更新 xf 与father[xf]的关系
- rank[xf]=(rank[y]-rank[x]+3+d)%3;
- }
- int main()
- {
- int totle=0;
- int i,n,k,x,y,d,xf,yf;
- scanf("%d%d",&n,&k);
- for(i=1;i<=n;++i)
- Make_Sent(i);
- while(k--)
- {
- scanf("%d%d%d",&d,&x,&y);
- //如果x或y比n大,或x吃x,是假话
- if(x>n||y>n||(d==2 && x == y))
- {
- totle++;
- }
- else
- {
- xf = Find_set(x);
- yf = Find_set(y);
- //如果x,f的父节点相同 ,那么可以判断给出的关系是否正确的
- if(xf == yf)
- {
- if((rank[x]-rank[y]+3)%3 != d-1)
- totle++;
- }
- else
- {
- //否则合并x,y
- Union(x,y,d-1);
- }
- }
- }
- printf("%d\n",totle);
- system("pause");
- return 0;
- }
poj1182(食物链)的更多相关文章
- 并查集专辑 (poj1182食物链,hdu3038, poj1733, poj1984, zoj3261)
并查集专题训练地址,注册登录了才能看到题目 并查集是一个树形的数据结构, 可以用来处理集合的问题, 也可以用来维护动态连通性,或者元素之间关系的传递(关系必须具有传递性才能有并查集来维护,因为并查集 ...
- POJ1182 食物链---(经典种类并查集)
题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submission ...
- NOI2001|POJ1182食物链[种类并查集 向量]
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65430 Accepted: 19283 Description ...
- POJ-1182 食物链 并查集(互相关联的并查集写法)
题目链接:https://cn.vjudge.net/problem/POJ-1182 题意 中文题目,就不写了哈哈 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃 ...
- poj1182食物链_并查集_挑战程序设计竞赛例题
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 65534 Accepted: 19321 Description ...
- [poj1182]食物链(并查集+补集)
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 64841 Accepted: 19077 Description ...
- poj1182(食物链)续
意 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用 ...
- POJ1182 食物链(并查集)
食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 55260 Accepted: 16210 Description ...
- (转)poj1182食物链
这题主要是看了http://blog.csdn.net/c0de4fun/article/details/7318642这篇解题报告,所以内容基本是转的!感谢大牛这么详细的把过程写的很清楚! 这道题目 ...
随机推荐
- 年前辞职-WCF入门(6)
前言 昨天早上去医院做入职体检,被告知要预约,本以为是要排队,我连视频都准备好了...结果就回来了.下午去了新公司那边找房子,2了,因为公司提供了班车列表,我既然就只在班车所经过的几个地方找,却遗漏了 ...
- 第二节Unity3D开发环境安装(windows系统)
这一节准备安装开发环境. 1. 首先先下载软件包:http://pan.baidu.com/s/1imYVv 4.2版本2.下载完后,解压会看到两个文件(运行第二个安装包) 3.准备安装,这 ...
- C# 使用XML序列化对象(二)
在C# 使用XML序列化对象(一)中描述了使用XML序列化对象的最简单的实现. 现在我们来看看稍微复杂一点的情况: 现有两个类:A和B,B是A的派生类,如下所示: public class A { p ...
- SVN命令使用详解
1.检出svn co http://路径(目录或文件的全路径) [本地目录全路径] --username 用户名 --password 密码svn co svn://路径(目录或文件的全路径) ...
- 使用GitHub进行团队合作
原文: Team Collaboration With GitHub GitHub已经成为的一切开放源码软件的基石.开发人员喜欢它,基于它进行协作,并不断通过它开发令人惊叹的项目.除了代码托管,G ...
- NS图绘制工具推荐
世界上要画NS图的人肯定很少,这种无聊的东西= = 我根据个人经验和直觉,推荐三个套工具. 一.签字笔(铅笔+橡皮)+作业纸+拍照的手机 鉴于我以前手绘版ns图已经找不到了,就用室友之前画的做个例子. ...
- BZOJ1207 [HNOI2004]打鼹鼠
Description 鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢 把头探出到地面上来透透气的.根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个n*n的网格中,在某些时刻鼹鼠会在某一个网格 ...
- RedGate .NET Reflector注册问题(反注册)
Reflector分为桌面版和VS集成版本,当我们使用注册机注册的时候如果注册了Standvard版本,那么我们的VS就不能集成查看,也不能Debug,那么这 显然不是我们想要的,我们会选择重新注册, ...
- 洛谷P1755 攻击火星
题目描述 一群外星人将要攻击火星. 火星的地图是一个n个点的无向图.这伙外星人将按照如下方法入侵,先攻击度为0的点(相当于从图中删除掉它),然后是度为1的点,依此类推直到度为n-1的点. 所有的点度统 ...
- Linux VPS新硬盘分区与挂载教程
通过fdisk -l我们可以看到/dev/xvdb(此名称因系统而异)容量有23.6G,而且没有分区,接下来我们对它进行分区和挂载 (红色字为需要输入的部分,黑色字为系统显示部分) 1.fdisk - ...