并查集:2020CCPC秦皇岛 Friendly Group

题目链接:点击这里

#include<bits/stdc++.h>//队友指点的并查集板子
using namespace std;
typedef long long ll; 
int s[300005];
int sum[300005];//花十个月时间学了个假算法
int ddd[300005];//绝了
int find(int u){
    
    //没听过带权并查集
	if(u==s[u]) return u;
	return s[u]=find(s[u]);
}
int main()
{
    
    
	int t;
	scanf("%d",&t);
	for(int uiu=1;uiu<=t;++uiu){
    
    
		int n,m,ans=0;
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n+5;++i){
    
    
			s[i]=i;
			ddd[i]=1;//点数 
			sum[i]=0;//边数 
		}
		for(int i=0;i<m;++i){
    
    
			int x,y;
			scanf("%d%d",&x,&y);
			int u=find(x),v=find(y);
			if(u!=v){
    
    
				s[v]=u;
				sum[v]+=sum[u]+1;//队友指点的并查集板子
    			ddd[v]+=ddd[u];
			}//并查集初始化 
			else{
    
    
				sum[v]++;
			}
		}
		for(int i=1;i<=n;++i){
    
    
			if(s[i]==i){
    
    
				if(sum[i]>ddd[i])
					ans=ans+sum[i]-ddd[i];
			}
		}
		printf("Case #%d: %d\n",uiu,ans);
	}
	return 0; 
}
#include<bits/stdc++.h>//第二个做法
using namespace std;
#define ll long long
int s[300005];
int in[300005];
int sum[300005];
int ddd[300005];
int find(int u){
    
    
	if(u==s[u]) return u;
	return s[u]=find(s[u]);
}
void init(int n){
    
    
	for(int i=0;i<=n+5;++i){
    
    
		in[i]=0;
		sum[i]=0;
		ddd[i]=0;
	}
}
int main()
{
    
    
	int t;
	scanf("%d",&t);
	for(int uiu=1;uiu<=t;++uiu){
    
    
		int n,m,ans=0;
		scanf("%d%d",&n,&m);
		init(n);
		for(int i=0;i<=n;++i) s[i]=i;
		for(int i=0;i<m;++i){
    
    
			int x,y;
			scanf("%d%d",&x,&y);
			++in[x],++in[y];
			int u=find(x),v=find(y);
			if(u!=v){
    
    
				s[v]=u;
			}
		}
		for(int i=1;i<=n;++i){
    
    
			sum[find(i)]+=in[i];
			++ddd[find(i)];//没学过带权并查集,单凭图论知识找点数和边数
			//如果把这两句改成
			/*sum[s[i]]+=in[i];
			++ddd[s[i]];*/
			//就会WA掉,看了2个小时硬是没看出来
		}
		for(int i=1;i<=n;++i){
    
    
			if(s[i]==i){
    
    
				if(sum[i]/2-ddd[i]>0)
					ans=ans+sum[i]/2-ddd[i];
			}
		}
		printf("Case #%d: %d\n",uiu,ans);
	}
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/qq_45695839/article/details/111397734