并查集模板

力扣269周赛的最后一题:题目描述
在这里插入图片描述
关于0到n-1,连通性的关键字的问题,很大可能是并查集模板。


定义全局变量:

vector<int> parent; //储存结点的祖先
vector<int> size; //储存以x为祖先的团体的大小
union_set(int n){ //初始化
    parent.resize(n);
    ranker.resize(n);
    for(int i = 0; i < n;++i){
        parent[i] = i; //初始每个结点的父节点都是自己
        size[i] = 1; //初始每个团体的大小都为1
    }
}

查询函数:

int find(int x){
	if(parent[x]==x) return x;
	parent[x]=find(parent[x]);
	return parent[x];
}

连接函数:

bool unionElement(int x,int y){
	int fx=find(x),fy=find(y); //查询x和y的祖先
	if(fx==fy) return false; //是一个团体里的,不用连接
	if(size[fx]<size[fy]) swap(fx,fy); //如果两个不是一个团体的,把小团体合并到大团体里面
	parent[fy]=fx; //fy是小团体,fx是大团体,小团体指向大团体
	size[fx]+=size[fy]; //fx的数量增加
	return true; //合并成功
}

判断是否连接函数:

bool isConnect(int x,int y){
	int fx=find(x),fy=find(y); //查找x和y祖先
	return fx==fy; //同一个祖先说明是连接的,返回true,反之不连接
}

孤立函数:

bool disConnect(int x){
	parent[x]=x; //祖先是自己的结点是孤立的结点或最大父结点
	return true;
}

本题需要按照开会时间排序,对数组排序处理。对于相同开会时间的情况,我们的解决办法就是两两连接同一时间开会的专家,会开完之后,孤立所有不知道秘密的专家。
主函数:

bool cmp(const vector<int>&a,const vector<int>&b){
	return a[2]<b[2]; //按照从小到大顺序排列
}

vector<int> findAllPeople(int n, vector<vector<int>>& ms, int fp) {
	sort(ms.begin(),ms.end(),cmp);
	int m=ms.size();
	unionElement(0,fp);
	for(int i=0;i<m;i++){
		int j=i+1;
		while(j<m&&ms[j][2]==ms[i][2]) j++;
		for(int k=i;k<j;k++){ //处理相同时间开会的专家
			unionElement(ms[k][0],ms[k][1]);
		}
		for(int k=i;k<j;k++){
			if(!isConnect(ms[k][0],0)){ //如果不连接的话,孤立两个结点
				disConnect(ms[k][0]);
				disConnect(ms[k][1]);
			}
		}
		i=j-1;
	}
	vector<int>ans;
	for(int i=0;i<n;i++){
		if(isConnect(0,i)) ans.push_back(i);
	}
	return ans;
}

完整代码:(稍微修改了下)

class Solution {
public:
    vector<int> parent; //储存结点的祖先
    vector<int> size;

    int find(int x){
	    if(parent[x]==x) return x;
	    parent[x]=find(parent[x]);
	    return parent[x];
    }

    bool unionElement(int x,int y){ 
	    int fx=find(x),fy=find(y); //查询x和y的祖先
	    if(fx==fy) return false; //是一个团体里的,不用连接
	    if(size[fx]<size[fy]) swap(fx,fy); //如果两个不是一个团体的,把小团体合并到大团体里面
	    parent[fy]=fx; //fy是小团体,fx是大团体,小团体指向大团体
	    size[fx]+=size[fy]; //fx的数量增加
	    return true; //合并成功
    }

    bool isConnect(int x,int y){
	    int fx=find(x),fy=find(y); //查找x和y祖先
	    return fx==fy; //同一个祖先说明是连接的,返回true,反之不连接
    }

    bool disConnect(int x){
	    parent[x]=x; //祖先是自己的结点是孤立的结点或最大父结点
	    return true;
    }

    static bool cmp(const vector<int>& a,const vector<int>& b){ //需要加static
	    return a[2]<b[2]; //按照从小到大顺序排列
    }

    vector<int> findAllPeople(int n, vector<vector<int>>& ms, int fp) {
        sort(ms.begin(),ms.end(),cmp);
        int m=ms.size();
        for(int i=0;i<n;i++){
            parent.push_back(i);
            size.push_back(1);
        }
        unionElement(0,fp);
        for(int i=0;i<m;i++){
		    int j=i+1;
		    while(j<m&&ms[j][2]==ms[i][2]) j++;
		    for(int k=i;k<j;k++){ //处理相同时间开会的专家
			    unionElement(ms[k][0],ms[k][1]);
		    }
		    for(int k=i;k<j;k++){
			    if(!isConnect(ms[k][0],0)){ //如果不连接的话,孤立两个结点
				    disConnect(ms[k][0]);
				    disConnect(ms[k][1]);
			    }
		    }
		    i=j-1;
	    }
        vector<int>ans;
	    for(int i=0;i<n;i++){
		    if(isConnect(0,i)) ans.push_back(i);
	    }
	    return ans;
    }
};

cmp函数前面需要加static或放在类外面做全局变量,详情见:
Annie Kim’s Blog
以及
initMyHeart’s Blog
又是为困难题流泪的一天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值