UVALive-7385-FlippingCards(并查集判环)

题目链接:点击打开链接

题目大意:

现在有一些卡片,卡片的每一面有一个数字,判断是否能否把所有的卡片摆在桌子上,满足:任意一个任意一个数字出现次数不超过一次(任何数字不能两次朝上)。

解题思路:

一:把每个数字看成一个点,卡片上的数字间连接一条边,那么当某些数字能连成一个环时,这些数字必须每个都要出现一次(仔细想想),既然这样,那么这个环上面的数字就不能再参与其余环的形成,也不能与其余环相连(再仔细想想),那么我们把所有边建好后,就是判断图中是否有相连的环,有的话就impossible。

二:开始想到并查集,但是没想到可以用来判断环的个数快哭了: 只需要开一个数组记录,每个父结点的参与成环的个数,合并的时候,把两个父节点的值相加就好了。

三:当然也可以DFS()遍历,不过相比并查集就慢多了。

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=5e4+10;
int p[maxn<<1],cnt[maxn<<1];
int FIND(int x){return p[x]==x?x:p[x]=FIND(p[x]);}
int main(){
    int T,n,u,v,x,y;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<=2*n;i++)p[i]=i;
        memset(cnt,0,sizeof cnt);
        for(int i=0;i<n;i++){
            scanf("%d%d",&u,&v);
            x=FIND(u);
            y=FIND(v);
            if(x==y)cnt[x]++;
            else {p[x]=y;cnt[y]+=cnt[x];}
        }
        int is_ok=1;
        for(int i=0;i<=2*n;i++){
            if(cnt[i]>1){is_ok=0;break;}
        }
        if(is_ok)printf("possible\n");
        else printf("impossible\n");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值