【POJ 2492】 A Bug's Life (条件并查集/bfs)

时间:2021-01-17 21:32:49

【POJ 2492】 A Bug's Life (条件并查集/bfs)


A Bug's Life
Time Limit: 10000MS   Memory Limit: 65536K
Total Submissions: 31920   Accepted: 10471

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.

Source

TUD Programming Contest 2005, Darmstadt, Germany


题目大意就是n个人 m对 每对表示a与b相恋 然后问存不存在同性恋

起初没想到并查集 用搜的方法 对于每对关系都建双向边 枚举每个人 如果还没搜过 就从这个人开始搜 把他所在的块搜完 既然是独立的块 就可以给该点一个初值0/1(男/女) 然后在搜的过程中如果出现0-0或1-1的情况就说明有同性恋 否则就一直搜下去

并查集就是在一般并查集上加个条件 表示该点与该集合根结点的关系0/1(同性/不同性) 如果出现新加的对a-b在一个集合里 且a、b与根的关系相同 则为同性恋


代码如下:

//搜
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#define VI vector<int>
#define VP vector<Point>
#define pr pair<int,int>
#define LL long long
#define fread() freopen("../in.in","r",stdin)
#define fwrite() freopen("../in.in","w",stdout)

#define MAX_P 10010

using namespace std;
const int INF = 0x3f3f3f;
const double esp = 1e-8;
const int msz = 500500;
const int mod = 1e9+7;

typedef struct Edge
{
    int v,next;
}Edge;

int sex[2020];//点的性别
Edge eg[2000200];
int head[2020];
int tp;

void Add(int u,int v)
{
    eg[tp].v = v;
    eg[tp].next = head[u];
    head[u] = tp++;
}

bool bfs(int u)
{
    queue <int> q;
    q.push(u);
    
    //独立的块先给起点一个初性别
    sex[u] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop();

        for(int i = head[u]; i != -1; i = eg[i].next)
        {
            //eg[i].v还未遍历过
            if(sex[eg[i].v] == -1)
            {
                sex[eg[i].v] = !sex[u];
                q.push(eg[i].v);
            }
            //出现0-0或1-1情况
            else if(sex[eg[i].v] != sex[u]^1) return true;
        }
    }

    return false;
}

int main()
{
    int t,m,n,x,y,root;

    scanf("%d",&t);
    for(int z = 1; z <= t; ++z)
    {
        scanf("%d %d",&n,&m);

        memset(head,-1,sizeof(head));
        tp = 0;
        while(m--)
        {
            //每一对加双向边
            scanf("%d %d",&x,&y);
            Add(x,y);
            Add(y,x);
        }

        printf("Scenario #%d:\n",z);

        int f = 0;
        memset(sex,-1,sizeof(sex));
        for(int i = 1; i <= n; ++i)
        {
            //如果i还没搜并且搜到同性(冲突-> 0-0或1-1)
            if(sex[i] == -1 && bfs(i))
            {
                f = 1;
                break;
            }
        }
        if(f) puts("Suspicious bugs found!\n");
        else puts("No suspicious bugs found!\n");
    }

    return 0;
}

//并查集版
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

using namespace std;

int pre[23333];
bool relax[23333];//0同 1不同

void init(int n)
{
    for(int i = 1; i <= n; ++i) pre[i] = i;
}

int Find(int x)
{
    //根和自己性别相同
    if(x == pre[x])
    {
        relax[i] = 0;
        return pre[x];
    }

    int p = Find(pre[x]);
    /*
    *当前点和原父亲 此时原父亲和现父亲关系已定 为relax[pre[x]] 则有如下关系
    *relax[x](压缩前跟原父亲关系)    relax[pre[x]](原父亲跟现父亲)   relax[x](压缩后跟现父亲关系)
    *0(同性)                     0(同性)                      0(同性)
    *0(同性)                     1(异性)                      1(异性)
    *1(异性)                     0(同性)                      1(异性)
    *1(异性)                     1(异性)                      0(同性)
    *
    */
    relax[x] ^= relax[pre[x]];
    return (pre[x] = p);
}

void Union(int u,int v)
{
    int k = Find(u);
    int r = Find(v);
    pre[k] = r;
    /*
    *
    *由于u与r要配对
    *则需要两集合合并后relax[u] = !relax[v] 则有如下关系
    *relax[u](合并前与k关系)   relax[v](合并前与r关系)  relax[k](合并后)
    *0(同性)                 0(同性)                 1(异性)
    *0(同性)                 1(异性)                 0(同性)
    *1(异性)                 0(同性)                 0(同性)
    *1(异性)                 1(异性)                 1(异性)
    */
    relax[k] = !(relax[u]^relax[v]);
}

int main()
{
    int t,n,m,u,v;

    scanf("%d",&t);

    for(int z = 1; z <= t; ++z)
    {
        scanf("%d %d",&n,&m);
        init(n);
        bool f = 1;

        while(m--)
        {
            scanf("%d %d",&u,&v);
            if(!f) continue;
            if(Find(u) == Find(v))
            {
                if(relax[u] == relax[v])
                {
                    f = 0;
                }
            }
            else Union(u,v);
        }

        printf("Scenario #%d:\n",z);
        if(f)
        {
            puts("No suspicious bugs found!\n");
        }else puts("Suspicious bugs found!\n");
    }

    return 0;
}