洛谷 P2024 食物链

题目:

题意:

输入若干句话,请求我们判断一共有几句是假话

分析:

这一题,典型的并查集例题升级版,难度还是有的,但一旦做出来,就会发现自己对并查集的熟练度增加了不止一倍,下面小编就来为大家分析一下这一题:首先,在题目中判定一句话是假话有3个条件:

• 当前的话与前面的某些真的话冲突,就是假话

• 当前的话中 X 或 Y 比 N 大,就是假话

• 当前的话表示 X 吃 X,就是假话

根据如此,我们可以一边读入,一边处理。后面两个两个条件是极好判断的,但难点就在于第一点,这时候,我们就引入一个全新的并查集概念:补集法,而这个概念的主要实现就是将数组开到x*n(x为任意一数)的范围。在这一题中,我们之所以要用到补集法是因为题目中出现了三种关系:A→BCA,与其说是一个食物链,倒不如是一个食物环,将食物链转化到了这一步,我们就不难看出每种动物都有三种关系:同类,猎物以及天敌。而我们使用补集法,就可以将同类储存到f[i]中,而猎物则放到f[i+n]中,同理,天敌就放到f[i+n*2]中。既然如此,那我们每读入两个动物,就看下他们的祖先是否符合当前的描述,如果不符合,那么累加,进入下一次循环,如果符合的话就将这两种动物进行合并。更具体的操作请看代码:

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
inline LL read() {
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
int f[150001];
int father(int i)//找i的祖先
{
	return f[i]==i? i:f[i]=father(f[i]);//加速递归
}
void hb(int x,int y)//合并两个集合
{
	int r1=father(f[x]),r2=father(f[y]);
	f[r1]=r2;
}
int main()
{
	int n,m;
	n=read();m=read();
	int ans=0;//ans为统计谎话数
	int a,b,c;
	for(int i=1;i<=n*3;i++) 
	  f[i]=i;
	for(int i=1;i<=m;i++)
	{
		a=read();b=read();c=read();
		if(b>n||c>n) {ans++; continue;}//先将两个简单的条件判断了
		if(b==c&&a==2) {ans++;continue;}
		if(a==1)//当我们可能是同类时:
		{
			if(father(b+n)==father(c)||father(b+n*2)==father(c)) {ans++;continue;}//如果你是我的猎物或天敌,那你肯定不是我的同类,所以ans+1
			hb(b,c);hb(b+n,c+n);hb(b+n*2,c+n*2);//如果真是同类,那么我的同类就是你的同类,我的猎物就是你的猎物,我的天敌也是你的天敌
		}
		else
		if(a==2)//当你可能是我的猎物时:
		{
			if(father(b)==father(c)||father(b+n*2)==father(c)) {ans++;continue;}//如果我们是同类或你是我的天敌,那么这句话就是假的
			hb(b,c+n*2);hb(b+n,c);hb(b+n*2,c+n);//如果你真是我的猎物,那么我的同类就是你的天敌,我的猎物就是你的同类,我的天敌就是你的猎物
		}
	}
	printf("%d",ans);//输出谎话数
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值