A Bug‘s Life POJ 2492 加权并查集

A Bug’s Life POJ 2492 加权并查集

传送门:http://poj.org/problem?id=2492

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 2000 2000) and the number of interactions (up to 1000000 1000000 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 KaTeX parse error: Expected 'EOF', got '#' at position 11: "Scenario #̲i:", where i is the number of the scenario starting at 1 1 1, followed by one line saying either " N o s u s p i c i o u s b u g s f o u n d ! " "No suspicious bugs found!" "Nosuspiciousbugsfound!" 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 Sample Output
2
3 3
1 2
2 3
1 3
4 2
1 2
3 4
Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!

Hint
Huge input,scanf is recommended.

题意
首先输入T表示有T组样例,每组样例第一行输入一个n和m,表示一共有n只虫,m次观察结果。紧接着m行每行输入虫子a和b的编号,表示a和b是异性关系。问在这些观察结果中是否有冲突。比如a和b是异性,b和c是异性,那么a和c是同性,如果出现观测结果a和c是异性,则冲突。

思路
如果有同一虫子出现在不同组观测结果中,则这些观测涉及到的虫子都是有关联的,比如说a和b是异性,b和c是异性,那么可以推出a和c是同性,此时如果观测c和d是异性,则可推出a和d是异性,b和d是同性。那么咱们可以用并查集把所有有关联的虫子分到同一集合中。
关系怎么表示呢?
假设现在有三组关系(无冲突情况)
a b
b c
c d
他们的关系图为
A Bug‘s Life POJ 2492 加权并查集
通过观察我们发现,和A距离是奇数的结点和它都是异性关系,距离是偶数的结点和它都是同性关系。
如果我们现在要求D和B的关系,那么先找到他们之间的距离 d i s ( D B ) dis(DB) dis(DB),即 d i s ( D B ) = ( d i s ( D C ) + d i s ( C B ) ) dis(DB)=(dis(DC)+dis(CB)) dis(DB)=(dis(DC)+dis(CB))
然后判断 d i s ( D B ) dis(DB) dis(DB)的奇偶即可。
从而我们并查集中的结点需要保存两个值:

struct node{
    ll pre , relation ;//结点的父亲,和结点与父亲的距离
}p[ N ];

查找父亲

ll Find( ll x ){
    if( p[ x ].pre == x ) return x ;
    ll tmp =  p[x].pre  ;
    //因为查找过程中压缩了路径,所以dis要更新,如图2,3
    p[ x ].pre = Find(tmp) ;
    p[ x ].dis += p[ tmp ].dis  ;
    return p[ x ].pre ;
}

A Bug‘s Life POJ 2492 加权并查集A Bug‘s Life POJ 2492 加权并查集

合并操作

void Merge( ll x , ll y ){ // r是x->y
    ll prey = Find( y ) ;
    ll prex = Find( x ) ;
    //x和prex是同性
    if( p[ x ].dis%2 == 0 ){
        //y和prey是异性
        if( p[ y ].dis%2 ) p[ prey ].dis = 0 ;
        else p[ prey ].dis = 1 ;
    }
    //x和prex是异性
    else{
        if( p[ y ].dis%2 ) p[ prey ].dis = 1 ;
        else p[ prey ].dis = 0 ;
    }
    p[ prey ].pre = prex ;
}

A Bug‘s Life POJ 2492 加权并查集
代码

#include<iostream>
#include<cstdio>
using namespace std ;
#define ll long long
const ll N = 1e5+9 ;
struct node{
    ll pre , dis ;
}p[ N ];
ll Find( ll x ){
    if( p[ x ].pre == x ) return x ;
    ll tmp =  p[x].pre  ;
    p[ x ].pre = Find(tmp) ;
    p[ x ].dis += p[ tmp ].dis ;
    return p[ x ].pre ;
}
void Merge( ll x , ll y ){ // r是x->y
    ll prey = Find( y ) ;
    ll prex = Find( x ) ;
    //x和prex是同性
    if( p[ x ].dis%2 == 0 ){
        //y和prey是异性
        if( p[ y ].dis%2 ) p[ prey ].dis = 0 ;
        else p[ prey ].dis = 1 ;
    }
    //x和prex是异性
    else{
        if( p[ y ].dis%2 ) p[ prey ].dis = 1 ;
        else p[ prey ].dis = 0 ;
    }
    p[ prey ].pre = prex ;
}
int main(){
    ll t , cas = 1 ; scanf("%lld",&t) ;
    while( t-- ){
        ll n , k ; scanf("%lld%lld",&n,&k);
        for( int i = 1 ; i <= n ; i ++ ){
            p[ i ].pre = i ; p[ i ].dis = 0 ;
        }
        ll f = 1 ;
        while( k-- ){
            ll x , y ;
            scanf("%lld%lld",&x,&y) ;
            ll prex = Find( x ) ;
            ll prey = Find( y ) ;
            if( prex != prey ) Merge( x , y ) ;
            else{
                //此时y和x连接在同一个父结点上,并且已经压缩路径了
                //所以他们的距离就是分别到达父节点的距离加和
                ll d = ( p[ y ].dis + p[ x ].dis )%2 ;//根据距离的奇偶判断关系
                if( d != 1 ) f = 0 ;
            }
        }
        printf("Scenario #%lld:\n",cas++);
        if( !f ) printf("Suspicious bugs found!\n\n") ;
        else printf("No suspicious bugs found!\n\n") ;
    }
return 0 ;
}

一种更简单的写法

#include<iostream>
#include<cstdio>
using namespace std ;
#define ll long long
const ll N = 1e5+9 ;
struct node{
    ll pre , relation ;
}p[ N ];
ll Find( ll x ){
    if( p[ x ].pre == x ) return x ;
    ll tmp =  p[x].pre  ;
    p[ x ].pre = Find(tmp) ;
    p[ x ].relation = ( p[ x ].relation + p[ tmp ].relation )%2 ;
    return p[ x ].pre ;
}
void Merge( ll x , ll y , ll r ){
    ll prey = Find( y ) ;
    ll prex = Find( x ) ;
    p[ prey ].relation =
    ( p[ x ].relation - p[ y ].relation - r + 2 )%2 ;
    p[ prey ].pre = prex ;
}
int main(){
    ll t , cas = 1 ; scanf("%lld",&t) ;
    while( t-- ){
        ll n , k ; scanf("%lld%lld",&n,&k);
        for( int i = 1 ; i <= n ; i ++ ){
            p[ i ].pre = i ; p[ i ].relation = 0 ;
        }
        ll f = 1 ;
        while( k-- ){
            ll x , y ;
            scanf("%lld%lld",&x,&y) ;
            ll prex = Find( x ) ;
            ll prey = Find( y ) ;
            if( prex != prey ) Merge( x , y , 1 ) ;
            else{
                ll d = ( p[ y ].relation - p[ x ].relation + 2 )%2 ;
                if( d != 1 ) f = 0 ;
            }
        }
        printf("Scenario #%lld:\n",cas++);
        if( !f ) printf("Suspicious bugs found!\n\n") ;
        else printf("No suspicious bugs found!\n\n") ;
    }
return 0 ;
}
上一篇:Oracle报错,ORA-28001: 口令已经失效


下一篇:长期计划