• POJ 1182 食物链(并查集)


    POJ 1182 食物链

    食物链
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 83505   Accepted: 24978

    Description

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。 
    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 
    有人用两种说法对这N个动物所构成的食物链关系进行描述: 
    第一种说法是"1 X Y",表示X和Y是同类。 
    第二种说法是"2 X Y",表示X吃Y。 
    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 
    1) 当前的话与前面的某些真的话冲突,就是假话; 
    2) 当前的话中X或Y比N大,就是假话; 
    3) 当前的话表示X吃X,就是假话。 
    你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。 

    Input

    第一行是两个整数N和K,以一个空格分隔。 
    以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 
    若D=1,则表示X和Y是同类。 
    若D=2,则表示X吃Y。

    Output

    只有一个整数,表示假话的数目。

    Sample Input

    100 7
    1 101 1 
    2 1 2
    2 2 3 
    2 3 3 
    1 1 3 
    2 3 1 
    1 5 5
    

    Sample Output

    3

    分析:由于N和K很大,所以必须高效地维护动物之间的关系,并快速判断是否产生了矛盾。并查集是维护 “属于同一组” 的数据结构,但是在本题中,并不只有属于同一类的信息,还有捕食关系的存在。因此需要开动脑筋维护这些关系。

    对于每只动物i创建3个元素i-A, i-B, i-C, 并用这3*N个元素建立并查集。这个并查集维护如下信息:

    ① i-x 表示 “i属于种类x”。

    ②并查集里的每一个组表示组内所有元素代表的情况都同时发生或不发生。

    例如,如果i-A和j-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。因此,对于每一条信息,只需要按照下面进行操作就可以了。

    1)第一种,x和y属于同一种类———合并x-A和y-A、x-B和y-B、x-C和y-C。

    2)第二种,x吃y—————————合并x-A和y-B、x-B和y-C、x-C和y-A。

    不过在合并之前需要先判断合并是否会产生矛盾。例如在第一种信息的情况下,需要检查比如x-A和y-B或者y-C是否在同一组等信息。

    code:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int MAX_N = 50000;
    const int MAX_K = 100000; 
    int par[MAX_N*3+1]; //父亲
    int N, K;
    void init(int n) {
        for(int i = 1; i <= n; i++) par[i] = i;
    } 
    int find(int x) {
        if(par[x] == x) return x;
        return par[x] = find(par[x]);
    } 
    void unite(int x, int y) {
        int u = find(x);
        int v = find(y);
        if(u != v) par[u] = v;
    } 
    bool same(int x, int y) { return find(x) == find(y); } 
    void solve() {
        init(N*3);
        int ans = 0;
        int t, x, y;
        for(int i = 0; i < K; i++) {
            scanf("%d%d%d", &t, &x, &y);
            if(x < 0 || x > N || y < 0 || y > N) {
                ans++;
                continue;
            }
            if(t == 1) {
                if(same(x, y+N) || same(y,x+N)) ans++;
                else {
                    unite(x, y);
                    unite(x+N, y+N);
                    unite(x+N*2, y+N*2);
                }
            } else {
                if(same(x, y) || same(y, x+N)) ans++;
                else {
                    unite(x, y+N);
                    unite(x+N, y+2*N);
                    unite(x+N*2, y);
                }
            }
        }
        printf("%d
    ", ans);
    }
    int main() {
        scanf("%d%d", &N, &K);
        solve();
        return 0;
    }
    作者:kindleheart
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    疯狂
    绝对基金的最爱,今年推荐
    蛛丝马迹中愤怒的老总
    值得作一年投资的股票
    狂牛终于被制服了,一起来享受盛宴吧(公布一些数据)
    敬而远之
    发现一庄两股
    一下表格大家好好研究吧
    怎样申购新股以及申购技巧
    股市比女人还善变
  • 原文地址:https://www.cnblogs.com/kindleheart/p/8591008.html
Copyright © 2020-2023  润新知