C - 食物链(poj-1182)

食物链

时间限制:1000 ms | 内存限制:65535 KB

描述
动物王国中有三类动物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),输出假话的总数。

输入
第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。
输出
只有一个整数,表示假话的数目。
样例输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
样例输出
3

这道题很经典,加深了我对并查集的理解与应用,去网上看的代码,有篇博客非常简洁,解题关键代码就只有7.8行的样子吧。没有很详细的注释,就这7,8行,看了我足足6.7小时,

收获挺大,我想把这题关键的部分写下来,纪念一下我的劳动,顺便也许能帮到人吧。

这是我参考的一篇博客:很详细,但是说得有点太多了,我都看得累了,代码也有点多了。。。下面的代码才是我说的只有7行关键的简洁代码,我写的类似与那篇博客

http://blog.csdn.net/c0de4fun/article/details/7318642

这道题的代码很精巧,先说总体思路

刚拿到这题,我想的是能不能将之化为3个并查集ABC,然后每个并查集头结点都记录着这类动物是什么属性,然后发现,根本行不通,因为不好确定到底是哪种属性的动物

这个的思路是将所有说到的动物都放在一个并查集,就是说只要有关系,就放一起。

find_head()找了头结点还压缩了路径到只有两层,这样就很容易判断两者的关系了,如果是同一个头结点通过对头结点的关系r[ ]很简单,

如果不在一个头结点,就说明没有关系嘛。肯定是真话,然后直接接起来就行了。接起来要自己推导个公式,难住我很久。。。等下说

f[N]是存某号动物的父节点的编号,r[N]是对父节点的关系 0 同类,1被父节点吃,2吃父节点 

find_head()函数递归不但找了头结点,还将搜索路径上的节点都压缩路径,将它直接连接到了头结点,对递归熟悉的不难理解

关键在于确定对 爷爷节点 的那个公式上,穷举一下,然后就能很轻松的看出来的,像个三角形关系

          r[f[x]]   r[x]

  爷爷  父亲   儿子  儿子与爷爷 

   0      0       0      (r[x] +r[f[x]] )%3  

   0      1       1   

   0      2       2   

   1      0       1  

   1      1       2  

   1      2       0  

   2      0       2  

   2      1       0     

   2      2       1 

然后到了将并查集联合这个函数,

前面说了,用find_head()找头结点,并且直接连上头结点,然后判断fx,fy是否相等,等于就是直接连起来对吧,但是发现个四边形关系,所以化成两个三角形呗。

3-r[y]是 y的头结点 对 y 的关系,这个好理解吧,

d-1是 y 对 x 的关系,因为 d 原本是 x 对 y 的关系,减 1 正好反过来。

然后用上我们前面的find里面的那个对父节点的公式, (r[x] +r[f[x]] )%3  ,带进去,不久得到 y 的头结点对 x 的关系了,

然后再加上 x 对 x 的父节点的关系就得到了fy对fx的关系, 这不就分成了2个三角形,得到了 r[fy] =什么。

如果fx==fy,就说明x和y有个关系,因为只有两层,所以自己再枚举一下,就得到了这个公式 (r[y]-r[x]+3)%3!=d-1;

或者你足够理解那个find_head()的那个公式3-r[x]是 x 的头结点对 x 的关系与r[y]相加一下就是 y 对 x 的关系看是否等于d-1。

写完博客,发现更加理解这题了,也更加理解怎么推导公式啥的了,有收获。

 1 #include <stdio.h>
 2
 3 int const N=50005;
 4 int f[N];
 5 int r[N];
 6
 7 int find_head(int x)
 8 {
 9     int fx=x;
10     if (x!=f[x])
11     {
12         fx=find_head(f[x]);
13         r[x]=(r[x]+r[f[x]])%3;     //这是穷举可以轻松看出来的公式,压缩路径
14         f[x]=fx;
15     }
16     return f[x];
17 }
18
19 int Union(int d,int x,int y)
20 {
21
22     int fx=find_head(x);
23     int fy=find_head(y);
24     if (fx!=fy)
25     {
26         f[fy]=fx;
27         r[fy]=(3-r[y]+d-1+r[x])%3;      //很重要的一个公式,由find里面的公式推导过来
28         return 0;
29     }
30     if ((r[y]-r[x]+3)%3!=d-1) return 1;
31     return 0;
32 }
33
34 int main()
35 {
36     int n,k;
37     int d,x,y;
38     int ans=0;
39     scanf("%d%d",&n,&k);
40     for (int i=1;i<=n;i++)
41     {
42         f[i]=i;
43         r[i]=0;
44     }
45     while (k--)
46     {
47         scanf("%d%d%d",&d,&x,&y);
48         if (x>n||y>n||(x==y&&d==2))
49         {
50             ans++;
51             continue;
52         }
53         if (Union(d,x,y)) ans++;
54     }
55     printf("%d\n",ans);
56     return 0;
57 }

时间: 2024-10-11 15:53:40

C - 食物链(poj-1182)的相关文章

食物链 poj 1182

C - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1182 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述

洛谷 P2024 食物链 POJ 1182 Label:并查集Turbo

题目描述 动物王国中有三类动物 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 句话有的是真 的,有的是假的.当

食物链 POJ 1182(并查集)

Description 动物王国中有三类动物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句话有的是真的,有的是假的.当一句话满足下列三条之

食物链 POJ - 1182 (并查集的两种写法)

这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃C时,C必须吃A,路径压缩后,A被C吃. 然后就是带权并查集的模板了. 判断条件,当x和y在同一颗树上是, 如果说,x和y之间的关系是0,那么x和RA与Y和RA之间的关系必须相同才行.x和Y之间的关系是1,当S[y]=2时,S[x]=1,当s[y]=1时,s[x]应等于0,才能满足 所以判断条件为(

POJ 1182 食物链 [并查集 带权并查集 开拓思路]

传送门 P - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1182 Appoint description:  System Crawler  (2015-01-27) Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物

又见关系并查集 以POJ 1182 食物链为例

简单的关系并查集一般很容易根据给出的关系搞出一个有向的环,那么两者之间的关系就变成了两者之间的距离. 对于此题: 若u,v不在一个集合内,则显然此条语句会合法(暂且忽略后两条,下同). 那么将fu 变为 fv的儿子时需加一条权值为 w 的边,w 满足(w + ru)%3 = (rv+ (D == 1? 0 : 1))%3(ru,rv分别为u,v与fv的关系,即距离). 之所以在D == 2时加 1,是因为u吃v表明着u到fv的距离比v到fv的距离大1. 同理,D == 1时,表明两者到fv的距离

POJ 1182——食物链——————【种类并查集】

食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 1182 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一

poj 1182 食物链 (带关系的并查集)

  食物链 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 44835 Accepted: 13069 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类.

POJ 1182 食物链 Union Find题解

Union Find就是所谓的并查集. 本题做的很无语,最后发现居然是输入搞错,一直WA. 不能使用循环接受输入,否则是WA的,气死人,浪费那么多时间就为了这个. 难点: 1 构建关系树 2 构建公式 3 快速更新公式 要抽象思维出什么对应什么的关系和上面是逆关系,就是利用0,1,2构建出父子节点之间的关系值,我是这样去思考构建出准确无误的公式的. 这样的抽象度是挺高的,需要多多训练. 关系到数学和Union Find,难度还是挺高的,网上很多人解法了. 我这里就增加一个按权值更新的优化算法,和

POJ 1182 食物链【并查集】

题目链接:http://poj.org/problem?id=1182 此题利用并查集解决. 对于每只动物i创建3个元素i-A,i-B,i-C,并用这3*N个元素建立并查集. 1·i-x表示"i属于种类x" 2·并查集你的每一组表示组内所有元素代表的情况同时发生或不发生. 对于每一条信息,只需要按照下列操作即可: 1.第一种:x,y同类,合并x-A和y-A.x-B和y-B.x-C和y-C. 2.第二种:x吃y,,,合并x-A和y-B.x-B和y-C.x-C和y-A. 当然,在合并之前,