首页 > 代码库 > hdu 1829-A Bug's LIfe(简单带权并查集)

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:\nSuspicious bugs found!\n\n", z);42       else printf("Scenario #%d:\nNo suspicious bugs found!\n\n", z);43    }44 }
View Code