食物链 poj1182 并查集

问题描述

有N种动物,它们分为三类(A、B、C),它们之间的捕食关系为A->B->C->A。现在给出K条关于这些动物的关系,包括两种动物的捕食关系或者是同类。判断其中有多少条关系是错误(和前面的关系有矛盾)的。

问题分析

并查集能将同一种类的动物合并在一个集合中,但是这里需要表示捕食关系。这里x可以属于三类,那么最终合理的结果也可以分为3种,因此这里对结果合并,xA、xB和xC分别用来表示x属于三种类别。如果x和y是同一种类别,那么xA和yA、xB和yB以及xC和yC分别属于在一个集合中,同理x捕食y时xA和yB、xB和yC以及xC和yA分别属于同一集合。

算法实现

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

public class Main {

    public static void main(String[] args) {
        new Main().solve();
    }

    int N, K, D, X, Y;
    int[] parent = new int[150005];
    int[] rank = new int[150005];
    void solve() {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(System.out);
        try {
            String[] arr = in.readLine().split(" ");
            N = Integer.parseInt(arr[0]);
            K = Integer.parseInt(arr[1]);
            for (int i = 0; i <= 3 * N; i++) {
                parent[i] = i;
            }
            int ans = 0;
            for (int i = 0; i < K; i++) {
                arr = in.readLine().split(" ");
                D = Integer.parseInt(arr[0]);
                X = Integer.parseInt(arr[1]);
                Y = Integer.parseInt(arr[2]);
                if (check()) continue;
                ans++;
            }
            out.println(ans);
        } catch (Exception e) {
            e.printStackTrace();
        }
        out.flush();
    }


    private boolean check() {
        if (X > N || Y > N) return false;
        if (D == 1) {
            if (same(X, Y + N) || same(X, Y + 2 * N)) return false;
            union(X, Y);
            union(X + N, Y + N);
            union(X + 2 * N, Y + 2 * N);
        } else {
            if (same(X, Y) || same(Y, X + N)) return false;
            union(X, Y + N);
            union(X + N, Y + 2 * N);
            union(X + 2 * N, Y);
        }
        return true;
    }

    private void union(int x, int y) {
        int px = find(x);
        int py = find(y);
        if (px == py) return;
        if (rank[px] < rank[py]) {
            parent[px] = py;
        } else {
            parent[py] = px;
            if (rank[py] == rank[px]) rank[px]++;
        }
    }

    private int find(int x) {
        return parent[x] == x ? x : (parent[x] = find(parent[x]));
    }

    private boolean same(int x, int y) {
        return find(x) == find(y);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值