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 InputSample 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
他们的关系图为
图1
通过观察我们发现,和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 ;
}

在这里插入图片描述在这里插入图片描述

合并操作

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 ;
}

在这里插入图片描述
代码

#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 ;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值