ACM-POJ-No. 1182-食物链-并查集

题目

在这里插入图片描述

分析

给每个动物赋予三个节点(n,2n,3n),那就将一个动物扩展到了3个(x——>x_A 、x_B
x_C),这样就将并查集的节点数量扩展到3n,用并查集维护这 3n 个节点的信息。

(如果不太了解并查集的代码,可以参考下我的另外一篇博文:并查集简单介绍

那么把题目中的给的 K 条信息转换一下(且用并查集维护这个关系):

  1. 如果 x 和 y 两个动物是同类:
    (1)x_a 和 y_a 是同类;合并 x_a 和 y_a 。
    (2)x_b 和 y_b 是同类;合并 x_b 和 y_b 。
    (3)x_c 和 y_c 是同类;合并 x_c 和 y_c 。
  2. 如果 x 吃 y 说明:
    (1)x_a 吃 y_b;合并 x_a 和 y_b。
    (2)x_b 吃 y_c; 合并 x_a 和 y_b。
    (3)x_c 吃 y_a;合并 x_a 和 y_b。
  3. 如果 x 和 y 一定不是同类,说明存在以下情况:
    (1)要么 x 吃 y
    (eg:x_a 吃 y_b , 则x_a 和 y_b 在一个集合里…)
    (2)要么 y 吃 x
    (eg:y_a 吃 x_b ,则y_a 和 x_b 在一个集合里…)
  4. 如果 x 一定不吃 y ,说明存在以下情况:
    (1)要么 x 和 y 同类
    (eg:x_a 和 y_a 是同类,则x_a 和 y_a 在一个集合里…)
    (2)要么 y 吃 x
    (eg:y_a 吃 x_b ,则y_a 和 x_b 在一个集合里…)

坑:注意这里的输入用scanf 或者 用cin加上std::ios::sync_with_stdio(false); 不然会超时,通不过。

AC代码

#include<iostream>
#define Max_K 100000+5
#define Max_N 150000+5
using namespace std;
int T[Max_K],X[Max_K],Y[Max_K];//记录输入的K条信息
int N,K;//N个动物 K条信息

int par[Max_N];//记录每个结点i的父亲 ;每个动物有3个结点,表示ABC三类,x,x+N,x+2*N分别代表x-A x-B x-C
int rank[Max_N];//树的高度

void init(int n) { //初始化
	for(int i=0; i<n; i++) {
		par[i]=i;
		rank[i]=0;
	}
}

int find(int x) {//查找根节点
	if(par[x]==x)
		return x;
	return par[x]=find(par[x]);
}

void unite(int x,int y) {//合并
	x=find(x);
	y=find(y);
	if(x==y)
		return ;
	if(rank[x]<rank[y])
		par[x]=y;
	else {
		par[y]=x;
		if(rank[x]==rank[y])
			rank[x]++;
	}
}

bool same(int x,int y) {//判断是否同一类
	return find(x)==find(y);
}

void solve() {
	init(N*3);//初始化合并集,每个动物有3个结点,每个动物都有属于ABC三类,x,x+N,x+2*N分别代表x-A x-B x-C
	int ans=0;
	for(int i=0; i<K; i++) { //循环开始判断K条信息的正确与否
		int t=T[i];
		int x=X[i]-1,y=Y[i]-1;//把输入的动物编号改为0~N-1

		if(x<0 ||N<=x||y<0||N<=y) { //该动物编号 不合法
			ans++;
			continue;
		}
		if(t==1) { //x y是同类?
			if(same(x,y+N)||same(x,y+2*N)) { //如果x吃y 或者y吃x 说明是假话
				ans++;
			} else { //同类合并:每个x_ABC 和y_ABC 都合并为一类
				unite(x,y);
				unite(x+N,y+N);
				unite(x+N*2,y+N*2);
			}
		} else { //是x吃y的关系?
			if(same(x,y)||same(x,y+2*N)) { //如果x,y是同类  或者是y吃x的关系  说明是假话
				ans++;
			} else {//是吃的关系,将x与y的有可能的吃的关系都合并
				unite(x,y+N);//x_A吃y_B
				unite(x+N,y+2*N);//x_B吃y_C
				unite(x+N*2,y);//x_C吃y_A
			}
		}
	}
	printf("%d\n",ans);
}
int main() {
	scanf("%d%d",&N,&K);// //N个动物 K条信息
	for(int i=0; i<K; i++) {
		scanf("%d%d%d",&T[i],&X[i],&Y[i]);
	}
	solve();
}

收获

  1. 并查集的运用。
  2. 通过扩充动物来实现更简单的维护关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MORE_77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值