hdu 1829-A Bug's LIfe(简单带权并查集)

题意:Bug有两种性别,异性之间才交往, 让你根据数据判断是否存在同性恋,输入有 t 组数据,每组数据给出bug数量n, 和关系数m, 以下m行给出相交往的一对Bug编号 a, b。只需要判断有没有,按题目要求输出。这题有点坑的地方在于输出上多了一行空行,不PE都没注意到。

思路:

  用一个数组gender[i] 记录当前节点 i 与根节点的关系,parent[i]数组记录当前节点的父节点。 因为是带权并查集,在Find_Parent 时更新当前节点与根节点的关系,且路径压缩至根节点下, 所以不用像普通并查集一样开辟辅助路径压缩的数组,合并的时候不用路径压缩。

  由于只有同性、异性两种关系,所以用gender[]数组存0、1表示两种性别。根节点相同的且性别相同的则是同性恋。

  然后下面说说不好理解的 Find_parent和合并时 对gender[] 的更新。

  首先,初始化的时候所有节点的父节点都是自己,gender[]都为0。又因为合并时无需路径压缩,所以根节点的gender始终为0,这是推导其他子节点关系的关键。

  Find_parent:由根节点始终为0,我们可以得到在Find_Parent时当前节点 i 与根节点的更新公式:gender[i] = gender[i] ^ gender[ par[i] ] (^为异或). 即 i 和 par[i] 性别相同 则 i 和根节点是异性,否则 i 和根节点则为同性。

  合并操作:合并x, y,找到x, y的父节点a, b,合并par[a] = b, 作为 子节点的那个父节点对根节点的关系 由gender[x] 和 gender[y]决定, 由于多加了一条边,所以gender[a] = (gender[x] + gender[y] +1)%2.

  判断同性恋:Union()返回布尔值,如果x, y父节点相同且性别相同则直接返回true表示找到同性恋,否则返回false。其他合并操作如上。

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 #define maxn 2006
 5 int gen[maxn], par[maxn];
 6 int Find(int x)
 7 {
 8    if(par[x] == x) return x;
 9    int t = Find(par[x]);
10    gen[x] = gen[x]^gen[par[x]];
11    return par[x] = t;
12 }
13 bool Union(int x, int y)
14 {
15    int a = Find(x);
16    int b = Find(y);
17    if(a == b){
18       if(gen[x] == gen[y]) return true;
19       return false;
20    }
21    par[a] = b;
22    gen[a] = (gen[x]+gen[y]+1)%2;
23    return false;
24 }
25 
26 int main()
27 {
28    int t; cin>>t;
29    for(int z = 1; z <= t; z++){
30       int flag = 0;
31       int n, m; scanf("%d%d", &n, &m);
32       for(int i = 1; i <= n; i++) par[i] = i, gen[i] = 0;
33 
34       for(int i = 0; i < m; i++){
35          int a, b;  scanf("%d%d", &a, &b);
36          if(flag) continue;
37          flag = Union(a, b);
38       }
39 
40       if(flag)
41          printf("Scenario #%d:
Suspicious bugs found!

", z);
42       else printf("Scenario #%d:
No suspicious bugs found!

", z);
43    }
44 }
View Code

  

原文地址:https://www.cnblogs.com/ZiningTang/p/3845083.html