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;
    }
    
  • 相关阅读:
    Java进阶(七)布隆过滤器
    NIO面试题
    TCP/IP面试题
    SPRING面试题
    SpringBoot(五)原理剖析:Transaction原理
    SpringBoot(四)原理剖析:AOP原理
    SpringBoot(三)原理剖析:IOC原理
    SpringBoot(二)原理剖析:AutoConfiguration原理
    mysql 安全更新
    查看端口占用
  • 原文地址:https://www.cnblogs.com/water-mi/p/10303467.html
Copyright © 2011-2022 走看看