hdoj 1829 A Bug's Life 【带权并查集】

A Bug's Life

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10618    Accepted Submission(s): 3451


Problem Description
Background
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs.

Problem
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.
 


Input
The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.
 


Output
The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.
 


Sample Input
  
  
2 3 3 1 2 2 3 1 3 4 2 1 2 3 4
 


Sample Output
  
  
Scenario #1: Suspicious bugs found! Scenario #2: No suspicious bugs found!
Hint
Huge input,scanf is recommended.
 

这道题不是简单的并查集,因为这个并查集需要维护性别这个信息;
一开始想的直接用一个数组sex存储性别信息,这个数组初始化为0。1代表雄性,-1代表雌性。
碰到两个未鉴别性别的(就是sex[x] == 0 && sex[y] == 0)那么直接sex[x] = 1,sex[y] = -1;
碰到一个未鉴别性别的(就是sex[x] == 0 或者 sex[y] == 0)若sex[x] == 0,就sex[x] = -sex[y],y一样。
下面就是判断是否成环,然后提交了,就没有然后了。。。
拿一组数据来说:
4 3
1 2
3 4
1 3
这组是没有可疑的同性恋的,但我的代码是有的,所以我的代码是错误的。
正确思路:用一个数组love存在当前元素第一个恋爱的对象。
每次判断x,y:
若为love[x] == 0则说明该元素还未恋爱,就将当前恋爱对象y赋值给love[x]。
若不为0,就将该元素恋爱的对象与当前恋爱对象合并即merge(love[x], y);
y元素判断和x一样。
 
附上两种代码:
#include <cstdio>
#include <cstring>
#define MAX 2000+10
using namespace std;
int set[MAX];
int love[MAX];//存储第一个和i恋爱的人 
int n, m;
int k = 1;
int exist;
void init()
{
    int i;
    for(i = 1; i <= n; i++)
    {
        set[i] = i;
        love[i] = 0;//初始化为0 
    }
}
int find(int p)
{
    int t;
    int child = p;
    while(p != set[p])
    p = set[p];
    while(child != p)
    {
        t = set[child];
        set[child] = p;
        child = t;
    }
    return p;
} 
void merge(int x, int y)//合并同性 
{
    int fx = find(x);
    int fy = find(y);
    if(fx != fy)
    set[fx] = fy;
} 
void search()
{
    int i, x, y;
    exist = 0; 
    for(i = 0; i < m; i++) 
    {
        scanf("%d%d", &x, &y);
        if(exist)//已经找到 同性恋 下面不用处理 
        continue; 
        if(find(x) == find(y))//他们在同一个集合  
        {
            exist = 1;//同性恋 
            continue; 
        }
        if(love[x])//x已经有恋人
        {
            merge(love[x], y);//与x恋爱的人 和 y必须是同一性别  合并同性
        }
        else love[x] = y;
        if(love[y])//y已经有恋人 
        {
            merge(love[y], x);//与y恋爱的人 和 x必须是同一性别  合并同性
        } 
        else love[y] = x; 
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        init();
        search();
        printf("Scenario #%d:\n", k++);
        if(!exist)
        printf("No suspicious bugs found!\n");
        else
        printf("Suspicious bugs found!\n");
        printf("\n"); 
    }
    return 0;
}
 
二:
对于每只动物创建2个元素i-A,i-B,并用这2 乘 N 个元素建立并查集。
这个并查集维护如下信息: 
1,i-x 表示i属于种类x 。
2,并查集里的每一组表示组内所有元素代表的情况都同时发生或不发生。 
例如,如果i-A和i-B在同一个组里,就表示如果i属于种类A那么j一定属于种类B,如果j属于种类B那么i一定属于种类A。
因此,对于每一条信息,只需要按照下面进行操作就可以了。 
第一种:x和y属于异类 合并x-A和y-B,x-B和y-A;(x代表x-A,x+n代表x-B) 
第二种:查询,判断x-A和y-A,x-A和y-B; 
代码实现:
<pre class="cpp" name="code">#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAX 4000+10
using namespace std;
int set[MAX];
int n, m;
int k = 1;
void init()
{
	for(int i = 1; i <= 2*n; i++)
	set[i] = i;
}
int find(int p)
{
	int t;
	int child = p;
	while(p != set[p])
	p = set[p];
	while(child != p)
	{
		t = set[child];
		set[child] = p;
		child = t;
	}
	return p;
}
void merge(int x, int y)
{
	int fx = find(x);
	int fy = find(y);
	if(fx != fy)
	set[fx] = fy;
}
bool same(int x, int y)
{
	return find(x) == find(y);
}
void input()
{
	int x, y;
	int exist = 0;
	while(m--)
	{
		scanf("%d%d", &x, &y);
		if(exist) continue;
		if(same(x, y))
		{
			exist = 1;
			continue;
		}
		merge(x, y+n);
		merge(x+n, y);
	}
	printf("Scenario #%d:\n", k++);
	if(exist)
	printf("Suspicious bugs found!\n\n");
	else
	printf("No suspicious bugs found!\n\n");
}
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		scanf("%d%d", &n, &m);
		init();
		input();
	}
	return 0;
}
 

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值