hdu 1829 A Bug's Life (基础种类并查集)

先说说种类并查集吧。

种类并查集是并查集的一种。但是,种类并查集中的数据是分若干类的。具体属于哪一类,有多少类,都要视具体情况而定。当然属于哪一类,要再开一个数组来储存。所以,种类并查集一般有两个数组,一个存并查集内的父子关系,一个存各个节点所属的种类关系。

以这道题为例(题意在后面,如果没有读题,可以先看完题在来看这部分)——

这道题很明显,将bug分成两类,一公一母。但是实际上我们并不关心它是公的还是母的,只关心它们之间是同性还是异性。所以,我们可以设与并查集的根节点同性的为0,反之为1。所以,我们就需要在int mfind(int x)里加上一个对于种类进行的操作。这个操作需要不停地修改每个bug所属的种类。

需要反复修改的理由:每次合并,我们都会将两个集合合并成一个集合,此时就会有一个根节点变成普通节点。那么之前在这个根节点之后的节点所拥有的关系就需要修改。前面已经说了,我们设置的01关系是和根节点相关的关系,那么当根节点变化的时候,我们的对应关系就需要变化。

值得注意的是,这个修改并不需要立刻进行,对于消失的那个根节点上的子节点,只需要在下次查询的时候进行就可以(类似于离线操作有些人的代码在进行合并之后就进行了一次查找,目的就是马上将查找的节点的种族及时修改,个人认为这是没有必要的)。但是对于消失的那个根节点,我们则需要及时将它与仍然存在的根节点的关系及时修改,因为这里是首次合并时进行的种类关系确定,即,将单个节点合并成一个集合时进行的种类关系确定。

种类关系的确定所使用的运算十分巧妙,我只是大概明白,却还不是完全清楚。种族关系确定时,如果两者的种族相同,那么需要修改其中一方的种族,如果两者的种族不同,那么保持不变。当然,这是这道题的操作,不同的题目会有不同的要求。

题意——

有两种bug,一种是公的,一种是母的。

现在给他们配对,只能公配母,否则就会出bug了,问你他所提出的配对方式有没有bug。

输入——

第一行一个整数t,表示有t组数据。

接下来,每组数据第一行有两个整数n, m,表示共有n个虫子,m种配对。

接下来m行,每行两个整数a, b,表示一种配对。

输出——

输出是第几组数据

输出是否存在bug。

数据举例——

1

3 3

1 2

1 3

2 3

这里表示共有1组数据,这组数据包含3只bug和3种配对。

由于1可以与2配,1可以与3配,那么2, 3同性……所以这一组是个bug(这里又不兴gay和百合……)

上代码——

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6
 7 const int M = 2010;
 8
 9 int fm[M];
10 int n, m, t;
11 bool tp[M], flag;   //tp[]记录种族,flag记录是否存在bug
12
13 int mfind(int x)                //查询操作
14 {
15     if(fm[x] == x) return x;
16     int fx = fm[x];
17     fm[x] = mfind(fm[x]);
18     tp[x] = tp[fx]^tp[x];       //修改种族,对查询的子节点进行
19     return fm[x];
20 }
21
22 void mmerge(int x, int y)
23 {
24     int fx = mfind(x);
25     int fy = mfind(y);
26     //printf("%5d%5d\n", fx, fy);
27     if(fx != fy)                    //合并操作
28     {
29         fm[fy] = fx;
30         tp[fy] = tp[x]^tp[y]^1;     //修改种族,对消失的根节点进行
31     }
32     else if(tp[x] == tp[y]) flag = 1;   //如果两个节点属于同一并查集且种族相同,则出现bug
33 }
34
35 void init()         //各种数据初始化
36 {
37     memset(tp, 0, sizeof(tp));      //种类初始化,所有节点都和自己属于同一种类
38     flag = 0;                       //目前没有bug
39     scanf("%d%d", &n, &m);
40     for(int i = 1; i <= n; i++) fm[i] = i;  //并查集初始化,这个不用多说了吧
41 }
42
43 void work()
44 {
45     for(int i = 0; i < m; i++)
46     {
47         int a, b;
48         scanf("%d%d", &a, &b);
49         if(!flag) mmerge(a, b);     //不存在bug才进行并查集操作,
50     }
51 }
52
53 void output(int tm)
54 {
55     printf("Scenario #%d:\n", tm);
56     if(!flag) printf("No suspicious bugs found!\n");
57     else printf("Suspicious bugs found!\n");
58     //for(int i = 1; i <= n; i++) printf("%5d", tp[i]);
59     //printf("\n");
60     printf("\n");
61 }
62
63 int main()
64 {
65     //freopen("test.in", "r", stdin);
66     scanf("%d", &t);
67     for(int tm = 1; tm <= t; tm++)
68     {
69         init();
70         work();
71         output(tm);
72     }
73     return 0;
74 }

当然,这个代码里我使用的是抑或^符号来处理的,主要原因是这里一共只有两个种类(使用bool数组进行记录也是如此的原因),如果种类比较多,就需要使用%符号或者其他的方式处理了。

ps:我也是一边写博客一边思考的,在写完的时候对于这个算法的思路确实又清晰了不少,看来写博客还是很有用处的。

hdu 1829 A Bug's Life (基础种类并查集)

时间: 2024-10-01 21:47:43

hdu 1829 A Bug's Life (基础种类并查集)的相关文章

HDU 1829 A Bug&#39;s Life (种类并查集)

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1829 A Bug's Life Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 19429    Accepted Submission(s): 6206 Problem Description Background Professor H

hdu 1829 A Bug&#39;s Life(分组并查集(偏移量))

A Bug's Life Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9204    Accepted Submission(s): 2961 Problem Description Background Professor Hopper is researching the sexual behavior of a rare sp

hdu1829 A Bug&#39;s Life 基础种类并查集

题目的大意可以理解为:A爱B,B爱C ……给出一系列爱恋的关系,推断有没有同性恋. 思路是把相同性别的归为一个集合,异性的异性为同性. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2010; int f[N], r[N], flag; void init() { for(int i=1;i&

hdu 1829 A Bug&#39;s Life (基础并查集)

题目: 链接:点击打开链接 题意: 给定虫子的交配关系,确定实验是否支持教授的假设即没有同性恋或者不符合假设. 思路: 是一道基础的并查集题目.存在两个集合异性和同性,给出多组关系,看这两个集合有木有联系,即是否有同性恋. 定义一个数组sex[],sex[i]表示与编号i的性别相反的虫子编号.然后将和i虫子有联系的合并为同一个集合(认为是同性的).如果findset(u) == findset(v),出现了反常行为. 代码: #include <iostream> #include <c

A Bug&#39;s Life(种类并查集)(也是可以用dfs做)

http://acm.hdu.edu.cn/showproblem.php?pid=1829 A Bug's Life Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1829 Description Background Professor Hopper is researching the sexual behavior of a r

poj 2492 a bug&#39;s life 简单种类并查集

题意大致为找同性恋的虫子.... 这个比食物链要简单些.思路完全一致,利用取余操作实现关系之间的递推. 个人感觉利用向量,模和投影可能可以实现具有更加复杂关系的并查集. 1 #include<cstdio> 2 using namespace std; 3 const int MAXN=50010; 4 int fa[MAXN]; 5 int rel[MAXN]; // 0代表同类,1代表吃fa[i],2代表被吃 6 void _set(int n) 7 { 8 for(int i=1;i&l

HDU 3038 How Many Answers Are Wrong(种类并查集)

题目链接 食物链类似的题,主要是在于转化,a-b的和为s,转换为b比a-1大s.然后并查集存 此节点到根的差. 假如x的根为a,y的根为b: b - y = rank[y] a - x = rank[x] y - x = s 可以推出b - a = rank[y] - rank[x] + s; 并查集 延迟更新什么的,都忘了啊. 还有这题,如果是x--的话,记得更新0的根. #include <cstring> #include <cstdio> #include <stri

hdoj-1289-A Bug&#39;s Life【种类并查集】

A Bug's Life Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11386 Accepted Submission(s): 3709 Problem Description Background Professor Hopper is researching the sexual behavior of a rare specie

POJ-2492 A Bug&#39;s Life(种类并查集)

http://poj.org/problem?id=2492 题意: 给出一个T代表几组数据,给出一个n一个m,代表人的编号由1~n,m条命令,每条命令由两个数值组成,代表这两个人性别不同,问所有命令是否符合逻辑 两种写法: 第一种:带权并查集 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h&g