POJ - 1182 食物链 拓展并查集

题目链接

POJ-1182

题意

草原上有ABC三种动物,A吃B,B吃C,C吃A。编号1-n的n个动物,给定两个个体之间的关系,判断有几条关系是错误的。

思路

因为n个动物都是属于三种动物之一,那么可以做出如下判断:

  1. 当a,b动物是同类时,他们的食物都是同类,他们的天敌也是同类
  2. 当a吃b时,a的食物和b都是同类,a的天敌和b的食物都是同类,a和b的天敌都是同类。

于是我们可以开一个三倍大小的并查集,1-n代表动物们自己,2-n代表各个动物的食物,2n-3n就是他们的天敌。

那么关系给出ab是同类时,只要判断一下b和a的天敌是否是同类,b和a的食物是否是同类就可以判断是否正确。正确的话将a和b,a+n和b+n,a+2n和b+2n连接。

对于给出a吃b的关系,那么我们判断一下a和b是不是同类,a的天敌和b是不是同类即可,对于正确的,将a+n和b,a+2*n和b+n,a和b+2n连接即可。

代码

#include<iostream>  
#include<cmath>
#include<cstring>
#include<cstdio>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
using namespace std;
	typedef long long ll;
	const int maxn=160000;
	const int inf=0x3f3f3f3f;
	int fa[maxn];
	int ra[maxn];
	void init(){
    
    
		for(int i=0;i<maxn;i++){
    
    
			fa[i]=i;
			ra[i]=0; 
		}
		return ;
	}
	 
	int find(int x){
    
    
		return x==fa[x]?x:fa[x]=find(fa[x]);
	}
	
	void unite(int x,int y){
    
    
		x=find(x); y=find(y);
		if(x==y)
			return ;
		else if(ra[x]<ra[y]){
    
    
			fa[x]=y; 
		} 
		else{
    
    
			fa[y]=x;
			if(ra[x]==ra[y])
				ra[x]++;
		}
	}
	int main(){
    
    
		init();
		int n,k;
		scanf("%d%d",&n,&k);
		int ans=0;
		while(k--){
    
    
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			if(b>n||c>n||b<1||c<1){
    
    
				ans++;
				continue;
			}
			if(a==1){
    
    
				if(find(c+n)==find(b)||find(c+2*n)==find(b)){
    
    
					ans++;
					continue;
				}
				unite(b,c);
				unite(b+n,c+n);
				unite(b+2*n,c+2*n);
			}
			else{
    
    
				if(b==c||find(b)==find(c)||find(b+2*n)==find(c)){
    
    
					ans++;
					continue;
				}
				unite(b+n,c);
				unite(b+2*n,c+n);
				unite(b,c+2*n);
			}
		}
		printf("%d\n",ans);
	} 
	
	

猜你喜欢

转载自blog.csdn.net/TheSunspot/article/details/107770247