(并查集)擒贼先擒王

并查集是若干个集合,可以判断两个对象是否在一个集合中,从而判断它们需不需要进行一个操作。合并集合就是合并树,使两颗树指向同一个祖先节点。

有若n个强盗 有m个线索,每个线索中的两个强盗为同伙(倘若A与B是同伙,B与C是同伙,那么A与C也是同伙),判断有多少个独立的犯罪团伙。

样例数据:

10 9//10个强盗 9条线索

1 2

3 4

5 2

4 6

2 6

8 7

9 7

1 6

2 4

输出样例:

3

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool vis[105];
long long a[1005];
int n,m;
long long ans;
int getf(int v){                    //递归找 所在节点的boss 
    if(a[v]==v){                    //节点的值等于该序号 则是boss节点 
        return v;
    }
    else{
        a[v]=getf(a[v]);           //路径压缩 将每个节点的boss设置为 最终的boss值 
        return a[v];               //压缩后可以提高今后查找某节点最终boss(就是树祖先)的速度 
    }
}
void marge(int v,int u){           
    int t1=getf(v);
    int t2=getf(u);
    if(t1!=t2){                    //合并节点原则 右边向左边合并  即右边成为左边元素的子集  
        a[t2]=t1;
    }
}
int main() {
    cin>>n>>m;
    for(int i=1;i<=n;i++){           //初始化 设置每个节点的boss是自己 
        a[i]=i;
    } 
    int x,y;
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        marge(x,y);                 //合并同伙 
    }
    for(int i=1;i<=n;i++){            //扫描数组 找boss 
        if(a[i]==i) ans++;
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xusi/p/12632082.html