扩展并查集//食物链+虫子

虫子的那个题可能比这个食物链简单,但我是先看会了食物链,回头才看懂了虫子 

POJ 1182/食物链//扩展并查集

题目链接         acwing题库链接

 对于扩展并查集,理解可能还不够透彻,现在记录目前的理解状况

因为这个能形成一个环,能用扩展并查集来写

我们开一个三倍的长度,其中 1-m  表示 i 的同伴1是 f 【i】;在m - 2*m 区间里, 他的意思是 i 能吃 f【i】(食物);在2*m - 3*m 的区间里,意思代表 i 的天敌是 f 【i】。

当 a 能吃 b 是,因为这是一个环,所以我们能够得到

a 的朋友是 b 天敌 的朋友(敌人的敌人是朋友//环的原因

a 的食物是 b 的同类

a 的天敌是 b 的食物

上面三个情况代码表示为

    f[find(a)]=find(2*m+b);
    f[find(a+m)]=find(b);
    f[find(a+2*m)]=find(m+b);

 这个理解时,我们在来判断说谎的可能情况

一,        a   b   大于N

二,        D==1,如果存在 a 的食物时 b,或者 b 的食物时 a 

三,        D==2,如果 存在 a 的同伴时 b ,或者 b 的食物时 a 

说的话为假。

#include<iostream>
using namespace std;
const int N=1e6+5;
int f[N],ans=0;
int find(int x)
{
	if(f[x]!=x)
		f[x]=find(f[x]);
	return f[x];
}
int main()
{
	int m,n;
	scanf("%d%d",&m,&n);
	for(int i=1;i<=3*m;i++)
		f[i]=i;
	
	for(int i=1;i<=n;i++)
	{
		int o,a,b;
		scanf("%d%d%d",&o,&a,&b);
		
		if(a<=0||b<=0||a>m||b>m)
		{
			ans++;
		}
		else
		{
			if(o==1)
			{
				if(find(a)==find(b+m)||find(a+m)==find(b))
				{
					ans++;
					continue;
				}
				
				f[find(a)]=find(b);
				f[find(a+m)]=find(b+m);
				f[find(a+2*m)]=find(b+2*m);
			}
			else
			{
				if(find(a)==find(b)||find(b+m)==find(a))
				{
					ans++;
					continue;
				}
				
				f[find(a)]=find(2*m+b);
				f[find(a+m)]=find(b);
				f[find(a+2*m)]=find(m+b);
			}
		}
	}
	printf("%d\n",ans);
}

poj 2492/虫子//

 这个题目只需要维护敌对关系即可,同伴关系的维护不好或者不可能取维护。

#include<iostream>
using namespace std;
const int N=4040;
int f[N];
int find(int x)
{
	if(x!=f[x])
		f[x]=find(f[x]);
	return f[x];
}
int main()
{
	int T;
	cin>>T;
	for(int TT=1;TT<=T;TT++)
	{
		int m,n;
		cin>>m>>n;
		for(int i=1;i<=2*m;i++)		f[i]=i;
			
		int t=0;
		for(int i=1;i<=n;i++)
		{
			int a,b;
			cin>>a>>b;
			int c=find(a);
			int d=find(b);
			if(t)	continue;
			
			if(c==d)	t=1;
			else
			{
				f[find(a+m)]=find(b);
				f[find(b+m)]=find(a);
			}
		}
		cout<<"Scenario #"<<TT<<":\n";
		if(t)	cout<<"Suspicious bugs found!\n\n";
		else	cout<<"No suspicious bugs found!\n\n";
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值