种类并查集

HDU 1829     A Bug's Life

这是今天写的第三道并查集,有了前面两道的铺垫,写这一道很快就写完了,网上博客说说这是水题.............暴风哭泣,好吧不管我还是很开心的

题目大体意思就是额? 输入一对x,y表示的是异性关系,而在处理这个关系之前看下是否是同性关系,如果是同性关系的话,那么就是错的 大体就是这样子了

然后嗯 因为不确定每个人到底是女的还是男的所以其实是有两种可能的

那么我们就是设置pre【】为n最大的两倍   之后每次要处理的时候判断下   是否是同性 如果是那么就错了

emmm 理解的关键可能在于有几种可能性,这是我觉得种类并查集理解最最最最关键的一步,我暑假的时候写这个死都不理解。因为根据每种可能性去处理可能发生的事情大体就是这个样子

代码如下:

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=4020;
int pre[maxn]; 
int n,m;
void init()
{
	for(int i=1;i<=2*n;i++)
	pre[i]=i;
}
int ufind(int k) 
{  
    if(k==pre[k])
    return k;
    return pre[k]=ufind(pre[k]);
}  
void merge(int x,int y)
{
	int fx=ufind(x);
	int fy=ufind(y);
	if(fx!=fy)
	pre[fx]=fy;
}
bool same(int a, int b) 
{  
    return ufind(a) == ufind(b);  
}  
int main()
{
	int t,x,y;
	scanf("%d",&t);
	for(int u=1;u<=t;u++)
	{
		scanf("%d%d",&n,&m);
		init();
		int flag=0;
		while(m--)
		{
			scanf("%d%d",&x,&y);
			if(flag)continue;
			if(same(x,y)||same(x+n,y+n))
			flag=1; 
			merge(x,y+n);
			merge(x+n,y);
		}
		printf("Scenario #%d:\n",u);
		if(flag)printf("Suspicious bugs found!\n");
		else printf("No suspicious bugs found!\n");
		putchar('\n');
	}
	return 0;
}

 

 

POJ - 1182 

 

B - 食物链

这题可以说是种类并查集超级经典的题了,讲课的时候不愿意讲这题,是怕学弟妹们刚学一小时并查集就做这题无法接受,去年暑假做这题感觉要上天了 好言归正传

意思都懂 就是不知道怎么写?  我不知道别人怎么做的但是我做种类并查集的方法 是
我不知道这个东西它有多少种可能,所以我去模拟他有多少种可能,针对每一种可能 做出相对应的反应,,,,我觉得理解的关键在于他有多少种可能

我pre数组开成3倍,因为有A吃B,B吃C,C吃A  我不知道输入的是A还是B还是C

先把假话的条件2和3都弄出来判断出来,这个很好判断

主要就是1 ,当前话和前面的话冲突了那么就是假的,这个时候也不要去合并它

我的Merge(x,y)表示的是他们是同类就合并哦  还有就是 这题有三个关系!不是两个不是两个! 一个是同类关系,一个是被吃关系,一个是吃别的动物的关系!

当op = 1时表示的是同类! 所以啊,我们要判断他们是否有吃与被吃的关系对嘛

好我们开始假设!输入x,y  其实只要判断ABC随便一个的关系那我们判断A好了

假设x都是A 因为啊咋们三个ABC都是有处理的 所以判断一个就好

既然说当前是A是同类关系!  那么说明A还有吃的关系    被吃的关系

1.same(x, y + n)是否为真? 注意哦! 这个是判断B吃A  A是被吃的关系

2.same(x,y + 2n)是否为真? 注意哦!这边是判断A吃C  A是吃别的动物的关系哎!

当op = 2 时表示的是x吃y的关系啊  所以还有同类和被吃关系对嘛所以要判断啊

1.same(x, y )是否为真? 注意哦! 这个是判断A和B是平等关系

2.same(x+n,y)是否为真? 注意哦!这边反了对不对!  same(x, y + n)表示y吃x嘛  所以对调一下嘛表示 x被y吃哈哈被吃关系
 

#include<cstdio>
#include<algorithm> 
using namespace std;
const int maxn = 150000 + 10;
int pre[maxn];//因为我不知道它是a还是b还是c所以我开成了3倍 
int find(int x)
{
	if(x == pre[x])
		return x;
	else 
		return pre[x] = find(pre[x]);
}
void merge(int x,int y)
{
	int fx = find(x);
	int fy = find(y);
	if(fx != fy){
		pre[fx] = fy;
	}
	return;
}
bool same(int x, int y){
	return find(x) == find(y);
}
int main()
{	
	int n, m;
	scanf("%d %d",&n,&m);
	for(int i = 1; i <= 3 * n; i ++)
		pre[i] = i;
	int x, y, op;
	int ans = 0;
	for(int i = 1; i <= m; i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		//先判断假话的2和3条件 
		if(x > n || y > n || x < 1 || y < 1 || op == 2 && x == y)
		{
			ans ++;
			continue;
		}
		/*
		1表示的是同类 所以我们要判断下是否与吃和被吃的关系冲突了呢
		2表示的是吃的关系 所以我们要判断是否与同类关系和被吃的关系冲突了呢? 
		我的pre是用来表示他们是同类的关系那么。。。 
		*/
		//这边判断假话的1条件就是与前面的话冲突了
		if(op == 1)
		{
			if(same(x, y + n) || same(x, y + 2 * n))
			{
				ans++;	
				continue;
			}	
			merge(x, y);
			merge(x + n, y + n);
			merge(x + 2 * n, y + 2 * n); 
		}else
		{
			if(same(x, y) || same(x + n, y))
			{
				ans++;
				continue;
			}
			merge(x, y + n);
			merge(x + n, y + 2 * n);
			merge(x + 2 * n, y); 
		}
	}
	printf("%d",ans); 
	return 0;
}

 

 

C - Find them, Catch them

 POJ - 1703 

 

emmm就是判断他是否在相同的团伙中和第一个性别的那个是一个意思的都一样的思路

代码:

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2*1e5+10; 
int pre[maxn]; 
int n,m;
int ufind(int k) 
{  
    if(k==pre[k])
    return k;
    return pre[k]=ufind(pre[k]);
}  
void merge(int x,int y)
{
	int fx=ufind(x);
	int fy=ufind(y);
	if(fx!=fy)
	pre[fx]=fy;
}
bool same(int a, int b) 
{  
    return ufind(a) == ufind(b);  
}  
int main()
{
	int t,x,y;
	char str[10];
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
	    for(int i=0;i<=2*n;i++)
	    	pre[i]=i;
		while(m--)
		{
			scanf(" %s%d%d",str,&x,&y);
			if(str[0]=='D')
			{
				merge(x,n+y);
				merge(n+x,y);
			}else if(str[0]=='A')
			{
				if(same(x,n+y))
					printf("In different gangs.\n");
				else if(same(x,y))
					printf("In the same gang.\n");
				else 
				printf("Not sure yet.\n");				
			}
		}
	}
	return 0;
}

 

 

 

 

 

 


 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值