分类并查集[noi2001 食物链]

题目链接:http://cogs.pro:8081/cogs/problem/problem.php?pid=pxNJzxVPU

题目有三种动物,A吃B,B吃C,C吃A

即B是A的食物,A是B的天敌,以此类推。

因此有可以有三个集合,0-N表示动物,N-N+N表示其食物,N+N-N*3表示其天敌。

代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#define MAXN 50100
using namespace std;
int N, K, D, x, y;
int ans = 0;
int pre[MAXN * 3];             //n 是同类 n + n是食物, n * 3是天敌
 
int find(int x)
{
    if (x == pre[x])
        return x;
    return pre[x] = find(pre[x]);
}
 
void Union(int x, int y)
{
    pre[find(x)] = find(y);
}
 
int main()
{
    freopen("eat.in", "r", stdin);
    freopen("eat.out", "w", stdout);
    scanf("%d %d", &N, &K);
    for (int i = 0; i < N * 3; i++)
        pre[i] = i;
 
    while (K--)
    {
        scanf("%d %d %d", &D, &x, &y);
        if (x > N || y > N)
            ans++;
        else
        {
            if (D == 1)
            {       //x的食物是y或者x的天敌是y
                if (find(x + N) == find(y) || find(x + N * 2) == find(y))
                {
                    ans++;
                    continue;
                }
                else  //xy是同类,xy的食物是同类,xy天敌是同类
                {
                    Union(x, y);
                    Union(x + N, y + N);
                    Union(x + (N << 1), y + (N << 1));
                }
            }
            else
            {
                if (x == y || find(x) == find(y) || find(x) == find(y + N))   //y的食物和x是同类
                {
                    ans++;
                    continue;
                }
                else //x和y的天敌同类,x的食物和y同类,x的天敌和y的食物是同类
                {
                    Union(x, y + (N << 1));
                    Union(x + N, y);
                    Union(x + (N << 1), y + N);
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kxxy/p/11721368.html
今日推荐