并查集(种类并查集)POJ2492A Bug's Life解题报告

A Bug’s Life
Time Limit: 10000MS Memory Limit: 65536K
Total Submissions: 31531 Accepted: 10343
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
参考博客:http://mojijs.com/2014/04/141135/index.html
并查集有两个优化。
一、按秩合并
描述:就是在对两个不同子集连接时,按照rank来连,也就是rank低的连在rank高的下面。rank高的做父亲节点。
作用,这样类似维护了一棵树,树是rank高的在上。
二、路径压缩
描述:假如fa数组已经嵌套了N层,那么传统的做法去找祖先要做N次,当N很大时,这种做法很没效率。
这是朴素查找的代码,适合数据量不大的情况:

int findx(int x)
{
    int r=x;
   while(parent[r] !=r)
        r=parent[r];
   return r;
}
下面是采用路径压缩的方法查找元素:
int find(int x)       //查找x元素所在的集合,回溯时压缩路径
{
    if (x != parent[x])
    {
        parent[x] = find(parent[x]);     //回溯时的压缩路径
    }         //从x结点搜索到祖先结点所经过的结点都指向该祖先结点
    return parent[x];
}
上面是一采用递归的方式压缩路径, 但是,递归压缩路径可能会造成溢出栈,我曾经因为这个RE了n次,下面我们说一下非递归方式进行的路径压缩:
int find(int x)
{
    int k, j, r;
    r = x;
    while(r != parent[r])     //查找跟节点
        r = parent[r];      //找到跟节点,用r记录下
    k = x;        
    while(k != r)             //非递归路径压缩操作
    {
        j = parent[k];         //用j暂存parent[k]的父节点
        parent[k] = r;        //parent[x]指向跟节点
        k = j;                    //k移到父节点
    }
    return r;         //返回根节点的值            
}

题目描述:有N个虫子。科学家认为只有两只虫子不同性别时,才会发生关系。现在给你M个关系,让你判断是否存在同性恋。
并查集的应用。
两个种类,需要两个集合,只需要增加一个记录相反标记的数组OppoSex[N]并将相应的种类加到相应的集合上即可。
下面是代码:

 #include 
#define N 2002
int father[N];//性别相同的虫子在同一集合
int rank[N];
int OppoSex[N];//OppoSex[i]代表与i性别相反的虫子号
void init(int len){
    for(int i=1;i<=len;i++){
        father[i]=i;
        rank[i]=0;
        OppoSex[i]=0;
    }
}
int GetRoot(int x){
    if(father[x]!=x){
        father[x]=GetRoot(father[x]);//路径压缩
    }
    return father[x];
}

void Union(int a,int b){
    int x=GetRoot(a);
    int y=GetRoot(b);
    if(rank[x]>rank[y])//按秩合并,小树加到大树上
        father[y]=x;
    else{
        father[x]=y;
        if(rank[x]==rank[y])
            rank[y]++;
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int T,n,m,i,a,b,num=0,flag;
    scanf("%d",&T);
    while(num1;
        scanf("%d%d",&n,&m);
        init(n);
        for(i=1;i<=m;i++){
            scanf("%d%d",&a,&b);//认为输入的两个虫子性别不同(即可以发发生关系)
            if(!flag)continue;//已经找到,只需将剩下的数据输入完即可
            int x=GetRoot(a), y=GetRoot(b);
            if(x==y)flag=0;//当两只发生关系的虫子性别相同时,发现同性恋
            if(OppoSex[a]!=0)
                Union(OppoSex[a],b);//a的相反性别的虫子在之前出现过,且和b性别应当相同,所以两者应放到同意集合
            else OppoSex[a]=b;
            if(OppoSex[b]!=0)Union(OppoSex[b],a);//同理
            else OppoSex[b]=a;
        }
        printf("Scenario #%d:\n",++num);
        if(!flag)
            printf("Suspicious bugs found!\n\n");
        else
            printf("No suspicious bugs found!\n\n");

    }
    return 0;
}

你可能感兴趣的:(并查集)