poj1182 食物链(种类并查集)详解

poj 1182   http://poj.org/problem?id=1182

分析:这个题大意说的非常清楚了,就是求出假话的个数,题目中给的假话要求有三个

① 当前的话与前面的某些真的话冲突,是假话;

②当前的话中X或Y比N大,是假话;

③当前的话表示X吃X,是假话。

②和③很好判断了,最难的就是假话条件①啦!!    题中说有三种动物A,B,C;   A-->B-->C-->A(A吃B, B吃C,C又吃A), 形成一个环; 然而我们又没办法把所给的动物(数字代替)确切的分给哪一类。 那么就不分了,既然这三种动物构成一个环么,那么我们就将所有相关联的元素合并成一个集合。 集合中有一个代表元素(下面也可能叫根元素)。 通过元素与根元素的关系  来区别他们。 relation[i] = 0 表示与根元素同类relation[i] = 1 表示吃根元素的那类, relation[i] = 2 表示被根元素吃的一类。 通过元素与根元素的关系清晰的将他们分为三类,又不用确切表明哪一类。

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;

int n, m, d, x, y, fx, fy, sum, pre[50010], relation[50010];
//初始化集合
void init()
{
    for(int i = 1; i <= n; i++)
    {
        pre[i] = i;
        relation[i] = 0;
    }
}
int find(int a)//寻找最终代表元素
{
    int i, j;
    i = a;
    if(pre[a] == a)
        return a;
    else
    {
        j = pre[i];
        pre[i] = find(j);//通过递归方式
        relation[i] = (relation[i] + relation[j]) % 3;
        //这个地方关键。  边寻找根元素, 边得出和根元素的关系。   这通过
        //该元素和父亲元素的关系  还有  父亲元素和根元素的关系 求出。
        //这个关系式我是枚举后  总结的   下面有推出的过程。
    }
    return pre[a];
}
//在这我写了两个合并的函数Union1,Union2,主要是因为d = 1时和 d = 2时
//求relation的方程不同,这个方程在下面也有推到过程
void Union1(int a, int b)
{
    pre[fx] = fy;
    relation[fx] = (3 + (relation[b] - relation[a])) % 3;
}
void Union2(int a, int b)
{
    pre[fx] = fy;
    relation[fx] = (3 + (relation[b] - relation[a]) + 1) % 3;
}

int main()
{
    scanf("%d%d", &n, &m);
    init();
    sum = 0;
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &d, &x, &y);
        if(x > n || y > n || (d == 2 && x == y))
        {
            sum++;
            continue;
        }
        fx = find(x);
        fy = find(y);
        //若x和y的根元素不同,就代表至少其中一个元素不再集合里,需要合并元素
        if(fx != fy)
        {
            if(d == 1)
                Union1(x, y);
            else
                Union2(x, y);
        }
        //当x和y的根元素相同时,就代表他们都是集合里的啦!  这使得工作就关键啦!!
        //需要判断这是给的关系和原本存在的关系是否冲突, 如果冲突, 假话就得多一个咯!
        else if(fx == fy)
        {
            if(d == 1)
            {
                if(relation[x] != relation[y])
                    sum++;
            }
            if(d == 2)
            {
                if(relation[x] != (relation[y]+1) % 3)
                    sum++;
            }
        }
    }
    printf("%d\n", sum);
    return 0;
}

Union2  relation[fx] = (3 + (relation[b] - relation[a]) + 1) % 3;

x与根元素fx的关系 y与根元素fy的关系 fx与fy的关系 relation[b] - relation[a]
0                          0 1 0
1 0 0 -1
2 0 2 -2
0 1 2 1
1 1 1 0
2 1 0 -1
0 2 0 2
1 2 2 1
2 2 1 0

Union1      relation[fx] = (3 + (relation[b] - relation[a])) % 3;

x与根元素fx的关系 y与根元素fy的关系 fx与fy的关系 relation[b] - relation[a]
0 0 0 0
0 1 1 1
0 2 2 2
1 0 2 -1
1 1 0 0
1 2 1 1
2 0 1 -2
2 1 2 -1
2 2 0 0

find   relation[i] = (relation[i] + relation[j]) % 3;

i元素与父亲元素j的关系 j元素与根元素的关系 i元素与根元素的关系
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 0
2 0 2
2 1 0
2 2 1

poj2492 和这个题类似 , 他只是将A,B,C三类动物 变成 男,女两种类。relation可能是同类或异类。如果出现一对是同类那么说明 有异常。 relation关系式:   find寻找时relation[i] = (relation[i] + relation[j]) % 2;    合并时relation[fx] = (relation[a] + relation[b] + 1) % 2。

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;

int n, m, x, y, flag, pre[2010], relation[2010];
void init()
{
    for(int i = 1; i <= n; i++)
    {
        pre[i] = 1;
        relation[i] = 1;
    }
}
int find(int a)
{
    int r, i, j;
    r = a; i = a;
    if(pre[a] == a)
        return a;
    else
    {
        j = pre[i];
        pre[i] = find(j);
        relation[i] = (relation[i] + relation[j]) % 2;
    }
    return pre[a];
}
void Union(int a, int b)
{
    int fx = find(a);
    int fy = find(b);
    if(fx != fy)
        pre[fx] = fy;
    relation[fx] = (relation[a] + relation[b] + 1) % 2;
}
int main()
{
    int t, num; cin >> t;
    num = 0;
    while(num < t)
    {
        scanf("%d%d", &n, &m);
        init();
        flag = 0;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d", &x, &y);
            if(flag == 1)continue;
            int fx = find(x);
            int fy = find(y);
            if(fx != fy)
                Union(x, y);
            else if(fx == fy)
            {
                if(relation[x] == relation[y])
                {
                    flag = 1;
                    printf("rela%d == rela%d\n", x, y);
                }
            }
        }
        printf("Scenario #%d:\n", ++num);
        if(flag == 1)
            printf("Suspicious bugs found!\n\n");
        else if(flag == 0)
            printf("No suspicious bugs found!\n\n");
    }
    return 0;
}

时间: 2024-11-07 12:36:41

poj1182 食物链(种类并查集)详解的相关文章

NOI2001|POJ1182食物链[种类并查集 向量]

食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 65430   Accepted: 19283 Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同

POJ1182 食物链 【并查集变种】

挺简单的 N个元素扩展为 3*N个 i-A i-B i-C A吃B吃C吃A 挑战程序设计的89面 #include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <cmath> using namespace std; int N,K; const int MAX_N=333333; //并查集 int par[MAX_N]; int ran

poj 1182 食物链 种类并查集

食物链是并查集的进阶运用的一道非常经典的题目. 题目如下: 动物王国中有三类动物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句话有的是真的

POJ 1182食物链 种类并查集的经典

题目链接:http://icpc.njust.edu.cn/Problem/Pku/1182/ 题意:给出动物之间的关系,有几种询问方式,问是真话还是假话. 定义三种偏移关系: x->y 偏移量0时 x和y同类 x->y 偏移量1时 x被y吃 x->y 偏移量2时 x吃y 定义 rela[x]=rx->x; 如x,y不在同一个集合中, 由rx->ry=rx->x + x->y + y->ry=(rx->x)+(x->y)-(ry->y)可得

POJ-1182食物链(并查集的运用)

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句话有的是真的,有的是假的.当一句话满足下列三条之

POJ1182食物链(并查集)

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句话有的是真的,有的是假的.当一句话满足下列三条之

POJ1182食物链 (并查集)

第一反应就是和那个搞基的虫子的题很像(poj2492 http://www.cnblogs.com/wenruo/p/4658874.html),不过是把种类从2变成了3. 错在很白痴的地方,卡了好久…… 代码: /********************************************* Problem: 1182 User: G_lory Memory: 972K Time: 266MS Language: G++ Result: Accepted *************

poj1182 食物链(并查集 好题)

https://vjudge.net/problem/POJ-1182 并查集经典题 对于每只动物创建3个元素,x, x+N, x+2*N(分别表示x属于A类,B类和C类). 把两个元素放在一个组代表他们同时发生. 被不合法数据卡了几次. 1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<algorithm> 6 #in

并查集详解(转)

并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了.以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定.不分享出来真是对不起party了.(party:我靠,关我嘛事啊?我跟你很熟么?) 来看一个实例,杭电1232畅通工程 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的.最后要解决的是整幅图的连通性问题.比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块.像畅通工程这题,问还需要修

并查集详解(转自一个很有才的大神)膜拜

并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了.以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定.不分享出来真是对不起party了.(party:我靠,关我嘛事啊?我跟你很熟么?) 来看一个实例,杭电1232畅通工程 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的.最后要解决的是整幅图的连通性问题.比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块.像畅通工程这题,问还需要修