并查集

poj2492 A Bug’s Life

题目大意:输入互相交配的两只虫,检查是否存在同性恋情况…

对于此题,二分图染色较为局限不适用此题,拆点并查集要创建相对立的节点不适合此题,此题适合用种类并查集,边权存储两边节点是否为同一性别,是同一性别为1,不是同一性别为0,路径压缩时要注意维护更新。

解题思路:
将发生关系的两只虫聚合——能连接在一起的就不是一个性别的虫
对于两只虫,比较一下看发生过关系没,有同一个根节点就代表之前发生了关系,根节点不同就是之前没发生过关系;再看看这两只虫的性别,如果这两只虫发生过关系并且性别相同,即导出矛盾。

#include <bits/stdc++.h>
using namespace std;

int pre[20010];
int r[20010];//记录性别,r=0代表同性

int Find(int x) { //路径压缩,许多结点的父结点会改变,需要根据实际情况调整权值以保证其正确性 模板! 
    if(pre[x]==x) return x; //x的父亲是x, 表示找到根节点了,返回根节点 
    int t;
    t=pre[x]; //将x的父亲保存下 
    pre[x]=Find(pre[x]); //压缩路径,把x的父亲变成x父亲的父亲。。。 
    r[x]=(r[x]+r[t]+1)%2; //异或运算,维护节点x和父亲的关系,r[x]==0时和父亲同类,==1时和父亲异类 
    return pre[x]; //x的父亲 
}

void Union(int a, int b) {
    int x,y;
    x=Find(a); y=Find(b); //将a、b的父亲找出来 
    pre[x]=y; //让x认y做父亲 
    r[x]=(r[b]-r[a])%2; //更新x与父亲的关系:a和b本来不一个集合,祖先也就不同,r的值是1,现在让他们相同,即让他们的值异或一下 
}

int main() {
    int t, i, j, k, flag;
    int n, m, a, b;
    
    scanf("%d",&t); //场景数 
    for(k = 1; k <= t; k++) {
        flag=0;
        scanf("%d%d",&n,&m); //全部的虫子数量 观察到的交配次数 
        for(i=1; i<=n; i++) {
            r[i]=1;
            pre[i]=i; //初始化,先认自己做父 
        }
        
        for(i=1; i<=m; i++) {
            scanf("%d%d",&a,&b); //交配的两只虫子 
            if(Find(a)==Find(b)) { //根节点相同,a和b原来发生过关系---ab异性 
                if(r[a]==r[b]) { //同性 
                    flag=1; //矛盾 
                }
            }
            else Union(a,b); //ab原来没有关系,就将a的集合和b的集合合并 
        }
        if(flag) printf("Scenario #%d:\nSuspicious bugs found!\n\n",k);
        else printf("Scenario #%d:\nNo suspicious bugs found!\n\n",k);
    }
    return 0;
}

find函数用来路径压缩,Union函数为合并集合,均为模板

“进阶算法”专栏目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值