NOI 2001 食物链 解题报告 (并查集)

来源:互联网 发布:用户数据分析报告 编辑:程序博客网 时间:2024/04/27 16:25

在线评测:

http://codevs.cn/problem/1074/


整体思路:

做了关押罪犯和这道题,感觉对并查集有了更深刻的理解,并查集是什么,是用来维护关系的,并没有字面的集合意思那么简单。

这道题我们知道有三种生物,互相吃,那么我们怎么去维护这个关系呢,仔细想想可以发现,我们可以对于每个编号生物3个状态,分别表示他是A,B,C。这里用到一个小技巧,可以只开一个数组,就是x,表示他是a,x+n表示他是b,x+2 * n表示他是c。我们一定要记住一件事,并查集是用来维护关系的,我们无需确定他是A,B,还是C,只要关系不冲突就行,所以当我们读入两个编号的生物为同一物种时,就把他们的当a,b,c生物的状态都并到一个集合。当两个生物为捕食关系时,我们只要将x,y+n   x+n,y+ 2* n    x+2n, y并到一个集合就可以了。

当我在处理时,如果发现已经有冲突,判断为假话。 

我们可以来看一下,局部代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (d == 1)
        {
            if (getfa(x) == getfa(y + n) || getfa(x) == getfa(y + 2 * n))
            {
                ans++;
                continue;
            
            merge(x,y);
            merge(x+n,y+n);
            merge(x+2*n,y+2*n);
        }else
        {
            if (getfa(x) == getfa(y) || getfa(x) == getfa(2 * n + y))
            {
                ans++;
                continue;
            }
            merge(x,n+y);
            merge(x+n,y+n*2);
            merge(x+2*n,y);
        }


失误之处:

当时在处理a吃b的时候只考虑a,b为同一物种时为假话,实际上当b吃a时,这句话同样也是假话~


体会心得:

情况要考虑全面,对于熟悉的算法,要深刻理解其含义。


AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n,k,d,x,y,fa[500000],size[500000];
int nnn,ans;
int getfa(int x)
{
    if (fa[x] == x) return x;
    return fa[x] = getfa(fa[x]);
}
void merge(int x,int y)
{
    int s1 = getfa(x);
    int s2 = getfa(y);
    if (size[s1] < size[s2])
    {
        fa[s1] = s2;
        size[s2] += size[s1];
    }else
    {
        fa[s2] = s1;
        size[s1] += size[s2];
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    nnn = n * 3;
    for (int i = 1;i <= nnn;i++)
    {
        size[i] = 1;
        fa[i] = i;
    }
    for int i = 1;i <= k;i++)
    {
        scanf("%d%d%d",&d,&x,&y);
        if (x > n || y > n)
        {
            ans++;
            continue;
        }
        if (d == 2 && x == y)
        {
            ans++;
            continue;
        }
        if (d == 1)
        {
            if (getfa(x) == getfa(y + n) || getfa(x) == getfa(y + 2 * n))
            {
                ans++;
                continue;
            
            merge(x,y);
            merge(x+n,y+n);
            merge(x+2*n,y+2*n);
        }else
        {
            if (getfa(x) == getfa(y) || getfa(x) == getfa(2 * n + y))
            {
                ans++;
                continue;
            }
            merge(x,n+y);
            merge(x+n,y+n*2);
            merge(x+2*n,y);
        }
    
    printf("%d\n",ans);
    return 0;

0 0
原创粉丝点击