zoukankan      html  css  js  c++  java
  • Poj1182 食物链(并查集/带权并查集)

    题面

    Poj

    题解

    这里采用并查集的补集。

    $x$表示同类集合,$x+n$表示敌人集合,$x+n imes2$表示敌人的敌人集合。

    如果当前给出的是一对同类关系,就判断$x$是否吃$y$或者$y$是否吃$x$(冲突)。

    如果是真话,就将所有关系连在一起。

    反之,如果给出的是一对$x$吃$y$关系,就判断$x$是否吃了自己(矛盾)或者他们两个互相吃(冲突)。

    如果是真话,将$x$的敌人和$y$的敌人的敌人(朋友)连在一起,将$y$的敌人和$x$的敌人的敌人(朋友)连在一起,即$y$的敌人是$x$的朋友,将$y$丢进$x$的敌人集合中。

    上面这对话可能有点绕口,但是大概还是讲出来了,仔细理解一下吧...

    这里还有一个带权并查集的做法,但是并查集补集更好写(写起来更顺些)。

    #include <cstdio>
    #include <cstring>
    #define Rg register 
    
    const int N = 5e4 + 10;
    int n, k, fa[N * 3], cz, x, y, ans, nn;
    
    int find (int x) {
    	if (fa[x] != x) fa[x] = find (fa[x]);
    	return fa[x];
    }
    
    int unionn (int u, int v) {
    	int fu = find (u), fv = find (v);
    	fa[fv] = fu;
    }//v -> u
    
    int main () {
    	scanf ("%d%d", &n, &k);
    	nn = n * 3;
    	for (Rg int i = 1; i <= nn; ++i)
    		fa[i] = i;
    	while (k--) {
    		scanf ("%d%d%d", &cz, &x, &y);
    		if (x > n || y > n) {++ans; continue;}//依据2
    		if (cz == 1) {
    			if (find (x + n) == find(y) || find (y + n) == find (x)) {++ans; continue;}//依据1
    			unionn (x, y); unionn (x + n, y + n); unionn (x + (n << 1), y + (n << 1));
    		} else {
    			if (find (x) == find (y) || find (x) == find (y + n)) {++ans; continue;}//依据1&依据3
    			unionn (y + (n << 1), x); unionn (y, x + n); unionn (y + n, x + (n << 1));
    		}
    	}
    	printf ("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    函数式宏定义与普通函数
    linux之sort用法
    HDU 4390 Number Sequence 容斥原理
    HDU 4407 Sum 容斥原理
    HDU 4059 The Boss on Mars 容斥原理
    UVA12653 Buses
    UVA 12651 Triangles
    UVA 10892
    HDU 4292 Food
    HDU 4288 Coder
  • 原文地址:https://www.cnblogs.com/water-mi/p/10303467.html
Copyright © 2011-2022 走看看