poj 2492 A Bug's Life 二分图 并查集

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.

题意:
虫子有两种性别,有n只虫子,编号1~n,输入m组数据,每组数据包含a、b两只虫子,表示a、b为不同性别的虫子,根据输入的m组数据是否出现前后矛盾(如a、b在前面判断为同性,而后又得出a、b为异性)进行相应的输出。
思路:

种类并查集

这也算是种类并查集的一道经典例题了吧,题意就不多解释了,先写一些我对种类并查集的一些理解。

种类并查集比普通的并查集多一个relation数组,relation[i] 记录了 i 和 其直接父亲节点的关系,这个关系的表示因题目而异,种类并查集的重点和难点就是对这个relation数组的维护。种类
在这个题中,relation数组具体表示是:以0表示和父亲节点的性别相同,1表示和父亲节点的性别不同。初始时可设初值全部为0。在Find函数中进行路径压缩时,要注意同时维护relation数组,如果relation[i] 和 relation[ father[i] ] 的值相同( 此时relation[ father[i] ] 实际上表示的是 i 的 父亲节点与 i 的祖先节点之间的关系)都是1 或者都是 0,可以推测出此时若将 i 链接到其祖先节点的话,relation[i] 应该变为0。若值不相同,则应变为1;
在Union函数进行合并中,首先看看x 和 y是否在同一个集合中。如果在同一个集合中,那么再判断他们相较于祖先节点的关系,如果关系相同说明是同性恋。如果不在同一个集合里,就可以合并。合并之后要继续考虑这时relation数组的变化。在我们寻找变化规律之前,让我们再仔细的看看relation数组,如果你和我一样看过很多人的题解(汗……)你会发现很多人使用Rank数组来表示relation,其实这也是relation数组的本质,relation数组其实表示的正是节点的偏移量,不过不是递增或递减变化,而是0和1交替变化。如果明白了这一点,Union函数中的relation数组变化是不是就迎刃而解了呢?对!我们只要将两个节点的偏移量相减后再加一再%2,得到的就是新的偏移量。

#include <iostream>
#include <map>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxx=2005;
int n,m;
int pre[maxx];
int dis[maxx];
int flag;
int find(int x)
{
    if(x!=pre[x])
    {
        int t =pre[x];
        pre[x]=find(pre[x]);
        dis[x]=(dis[x]+dis[t]+1)%2;
    }
    return pre[x];
}
void join(int x,int y)
{
    int fx=find(x),fy=find(y);
    pre[fx]=fy;
    dis[fx]=(dis[y]-dis[x])%2;
}

int main()
{
//    std::ios::sync_with_stdio(false);
    int t,n,m,flag;
    scanf("%d",&t);
    int id=1;
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)//初始化
        {
            pre[i]=i;
            dis[i]=1;
        }
        flag=0;
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            if(find(a)==find(b))//判断两个虫子是否祖先相同
            {
                if(dis[a]==dis[b])//判断两个虫子的性别是否相同
                {
                    flag=1;
                }

            }
            else join(a,b);//合并两个虫子
        }
        if(flag)
        {
            printf("Scenario #%d:\nSuspicious bugs found!\n",id++);
        }
        else printf("Scenario #%d:\nNo suspicious bugs found!\n",id++);
        printf("\n");
    }
	return 0;
}

二部图染色法

用二部图染色法把虫子分成两拨,一直wa…目前不知道哪里错了
提一下代码吧(wa的代码)

#include <iostream>
#include <cstdio>

using namespace std;
const int maxx=1e6+7;
int e[maxx],ne[maxx],h[maxx],id;
int color[maxx];
int n,m;
void add(int a,int b)
{
    e[id]=b,ne[id]=h[a],h[a]=id++;
}
bool dfs(int u,int c)
{
    color[u]=c;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int n=e[i];
        if(!color[n])
        {
            if(!dfs(n,3-c)) return false;
        }
        else if(color[n]==c) return false;
    }
    return true;
}
void init()
{
    for(int i=0;i<maxx;i++)
    {
        e[i]=0;
        ne[i]=0;
        h[i]=-1;
        color[i]=0;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >>t;
    int d=1;
    while(t--)
    {
        id=0;
        bool flag=true;
        cin >>n>>m;
        init();
        int a,b;
        for(int i=0;i<m;i++)
        {
            cin >>a>>b;
            add(a,b),add(b,a);
        }
        for(int i=1;i<=n;i++)
        {
            if(!color[i])
            {
                if(!dfs(i,1))
                {
                    flag=false;
                    break;
                }
            }
        }
        if(!flag) printf("Scenario #%d:\nSuspicious bugs found!\n\n",d++);
        else printf("Scenario #%d:\nNo suspicious bugs found!\n\n",d++);
    }
    return 0;
}

(真的是玄学 同样的代码 前几天交就wa 今天复制过来交上去就ac了,我说怎么找不到自己哪里错了呜呜呜呜呜呜呜呜呜呜)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值