POJ 2492 A Bug's Life and POJ 1703 Find them, Catch them

A Bug's Life


并查集的应用。与食物链那到题目类似,对于关系明确的bug之间合并,用数组p[x]和d[x]分别表示x的父节点以及x与父节点之间的关系,我们可以假设d[x]=0表示x与p[x]是同性,d[x]= 1表示x与p[x]是异性。对于查操作的时候,我们不断的压缩路径,同时更新d[x]的值,这里d[x] = (d[x] + d[p[x]])%2,很容易推出来,具体看程序中find_x()函数。然后是合并操作,对于给定的x和y,我们先找到其根节点,然后合并根节点,这里画一下就能得出结论:d[ty] = (d[x] + 1 - d[y])%2,其中ty=find_x(y).具体看程序。本题需要注意的是:在读入数据的时候,要把每一组所对应的数据全部读完,并不能因为找到一组同性关系就退出。

/*
author   : csuchenan
LANG     : c++
algorithm: disjointset data structure 
*/

#include <cstdio>
#include <cstring>
#define maxn 2005
int p[maxn] ;
short d[maxn];

int N ;
int M ;

void init(){
    for(int i = 1 ; i <= N ; i ++){
        p[i] = i ;
        d[i] = 0 ;
    }
}

int find_x(int x){
    if(p[x] == x)
        return x ;
    int tx( find_x( p[x] ) ) ;

    d[x] = (d[x] + d[ p[x] ])%2 ;
    p[x] = tx ;
    return tx ;
}
void join(int x , int y){
    int tx = find_x(x) ;
    int ty = find_x(y) ;
    if(tx==ty)
        return ;
    d[ty] = (d[x] + 1 - d[y])%2 ;
    p[ty] = tx ;
    return ;
}

bool solve(){

    int x ;
    int y ;
    bool flag ;
    flag = 0  ;

    for(int k = 0 ; k < M ; k ++){
        scanf("%d%d" , &x , &y) ;
        if(!flag){
            int tx = find_x(x) ;
            int ty = find_x(y) ;

            if(tx == ty && (d[x] + d[y])%2==0){
                flag = 1 ;
            }
            join(x , y) ;
        }
    }
    return flag ;
}

int main(){
    int T ;
    int t(0) ;

    scanf("%d" , &T) ;

    while(t < T){
        scanf("%d%d" , &N , &M) ;
        init()  ;
        printf("Scenario #%d:\n" , ++t ) ;
        if( solve() )
            printf("Suspicious bugs found!\n") ;
        else
            printf("No suspicious bugs found!\n") ;
        printf("\n") ;
    }

    return 0 ;
}


POJ 1703 Find them, Catch them

这个题目和POJ2492相同,关系也是2元关系(由于只有两个gang),采用相同的办法,这里是查询x和y是不是在同一个gang里面,首先如果x和y的父节点是不同的,那么x与y之间的关系肯定不确定,然后如果父节点相同,那么如果d[x]与d[y]是相同的,或者(d[x]+d[y])%2==0,则说明x和y肯定在同一个gang里面,否则肯定在不同的gang里。

/*
author:csuchenan
LANG: c++
Algorithm: disjointset data structure
*/
#include <cstdio>
#include <cstring>

#define maxn 100005

int   p[maxn] ;
short d[maxn] ;
int N , M ;

void init(){
    for(int i = 1 ; i <= N ; i ++){
        p[i] = i ;
        d[i] = 0 ;
    }
}

int find_x(int x){
    if(x==p[x])
        return x ;
    int tx = find_x(p[x]) ;

    d[x] = (d[x] + d[ p[x] ])%2 ;
    p[x] = tx ;
    return tx ;
}

void join(int x , int y){
    int tx = find_x(x) ;
    int ty = find_x(y) ;
    if(tx==ty)
        return ;
    d[ty] = (d[x] + 1 - d[y])%2 ;
    p[ty] = tx ;
}

void solve(){
    char c ;
    int x ;
    int y ;

    for(int i = 0 ; i < M ; i++){
        getchar() ;
        scanf("%c%d%d" , &c , &x , &y) ;
        int tx = find_x(x) ;
        int ty = find_x(y) ;
        if(c=='A'){
            if(tx!=ty)
                printf("Not sure yet.\n") ;
            else if( (d[x] + d[y])%2==0 )
                printf("In the same gang.\n") ;
            else
                printf("In different gangs.\n") ;
        }
        else
            join(x , y) ;
    }
}
int main(){
    int T ;
    scanf("%d" , &T) ;

    while(T--){
        scanf("%d%d" , &N , &M) ;
        init()  ;
        solve() ;
    }

    return 0 ;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值