POJ1182: 食物链(并查集运用)
题目描述
动物王国中有三类动物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 sample
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
output sample
3
思路整理
(这道题困扰了我挺久,因为一直看不懂并查集,以下是按照自己的思路试着领会了一下并查集在这道题中的运用)
1.首先,这道题中,我们无法根据条件判断出每个动物具体属于A B C中的哪一类,因此我们换个思路,把题目转换为判断每句话所体现的两只动物之间的相对关系是否与到目前为止得到的信息有冲突。
2.在判断每条语句时,首先将只根据当前语句信息就能判断必然错误的语句直接判为假,具体情况有:
(1):x与y取值超过边界条件:x > N || y > N
(2):x吃y,但x与y为同一点:D=2, x == y
3.在无法通过当前语句信息判断对错时,查找之前判断为真的语句中与x和y有关的信息,在对比相关信息和当前信息,如果有冲突记为假,没有冲突就更新x与y的相关信息。
继续整理
现在我们已经把判断条件分成了2,3两步,我们主要关注第三步的实现过程。
我们假设x和y在当前语句之前已经和别的动物间产生了相对关系。
如上图所示,假设在这条语句前,我们已知x吃q,q=w,w被z吃。同时,我们已知t吃p,p吃z。这意味着我们间接得知了x与z的相对关系以及t与z的相对关系,因此,我们也应该能判断出x与t的相对关系,将x与t的相对关系与当前语句进行对比,即能判断当前语句是否为假。
接着我们思考另一个问题,在x与z中间还存在q与w两点,这两点在我们的实际运算中并没有起到任何作用,因此我们希望直接在x与z之间建立相对关系,而不是通过其他点来建立联系。更进一步来说,我们希望每一个确定了相对关系的集合中(在上图中,该集合为{x,q,w,z,p,t})的每一个元素能确定一个共同的祖先(根节点),使得当我们在一次碰到集合中存在的元素时,能立即通过他们与共同祖先的相对关系来判断他们之间的关系。
要做到这一步,我们需要压缩集合中的每个点到根节点间的距离,以上图x为例,我们不断沿着x进入它的父节点,直到最终找到根节点z,并将z的指针赋给路径中的每一个点,这样我们就实现了路径压缩,需要特别注意的是,这道题中我们我们在更改父节点的过程中,需要同时维护子节点与父节点的相对关系。
那么如果当前语句中的两个点x与y不属于同一集合(即拥有不同的根节点)时,应该怎么处理呢?
很简单,因为在当前语句之前,x与y之间还没有建立任何的相对关系,所以没有任何证据表明当前语句为假,根据题意,我们即把当前语句当做真,因此我们得到了x与y之间的相对关系。这时,我们将y的根节点的父节点置为x的根节点,我们就将包含x与y的两个不同的集合合并在一起产生了一个新的集合。