食物链 POJ - 1182 (并查集)

在这里插入图片描述

题解: 很明显看到这种类别的合并和判断的题面一定就是并查集了, 但对于这题我们似乎不能够直接套模板来用, 因为无法直接确定种类, 而且要求得也只是假话的数量, 需要使用一点思维.
对于第i个动物a[i], 使用a[i], a[i+N], a[i+2*N], 分别表示i - A, i - B, i - C, 也就是当前动物和ABC三种动物的可能关系, 如果两数相同, 则可能同时发送

  • 对于1操作, 我们合并(a[x], a[y]), (a[x+N], a[y+N]), (a[x+2N], a[y+2N])
  • 对于2操作, 我们合并(a[x], a[y+N]), (a[x+N], a[y+2N]), (a[x+2N], a[y)
  • 如果产生冲突无法合并则ans++
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const LL maxn = 5*1e4+10;

int N, K, opt, x, y;
int a[maxn*3], rk[maxn*3];
void init(int n){
    for(int i = 1; i <= n; i++)
        a[i] = i;
}
int findr(int n){
    if(a[n] == n) return n;
    else return a[n] = findr(a[n]);
}
bool isSame(int a, int b){ return findr(a)==findr(b);}
void unite(int x, int y){
    x = findr(x), y = findr(y);
    if(x == y) return;
    if(rk[x] < rk[y])
        a[x] = y;
    else{
        a[y] = x;
        if(rk[x]==rk[y]) rk[x]++;
    }
}
int main()
{
    scanf("%d%d",&N,&K);
    init(N*3); //表示 i-a, i-b, i-c的关系
    int ans = 0;
    while(K--){
        scanf("%d%d%d",&opt,&x,&y);
        if((opt!=1&&opt!=2) || x<1||x>N || y<1||y>N){
            ans++;
            continue;
        }

        if(opt == 1){
            if(isSame(x, y+N) || isSame(x, y+2*N))
                ans++; //冲突: x和y不是同一组
            else
                unite(x, y), unite(x+N, y+N), unite(x+2*N, y+2*N);
        }else{
            if(isSame(x, y)||isSame(x, y+2*N))
                ans++; //冲突: x无法吃y
            else
                unite(x, y+N), unite(x+N, y+2*N), unite(x+2*N, y);
        }
    }
    printf("%d\n",ans);

	return 0;//
}

猜你喜欢

转载自blog.csdn.net/a1097304791/article/details/87074965