Social Network(并查集)

Social Network原题

题面翻译

给定 n n n 个点, d d d 条规定,每条规定有两个参数 x i , y i x_i,y_i xi,yi,表示 x i x_i xi y i y_i yi 必须连通。

∀ i ∈ [ 1 , d ] \forall i\in[1,d] i[1,d],求在满足 [ 1 , i ] [1,i] [1,i] 的规定的前提下恰好连 i i i 条边的无向图中度数最大的点的度数(就是联通块的边数)。

2 ≤ n ≤ 1 0 3 , 1 ≤ d ≤ n − 1 , 1 ≤ x i , y i ≤ n , x i ≠ y i 2\le n\le 10^3,1\le d\le n-1,1\le x_i,y_i\le n,x_i\not=y_i 2n103,1dn1,1xi,yin,xi=yi

样例 #1

样例输入 #1

7 6
1 2
3 4
2 4
7 6
6 5
1 7

样例输出 #1

1
1
3
3
3
6

样例 #2

样例输入 #2

10 8
1 2
2 3
3 4
1 4
6 7
8 9
8 10
1 4

样例输出 #2

1
2
3
4
5
5
6
8

解题思路

  • 思路:这题要求的是最大的度,即最大的连通块里面的边数,很显然,这是一道并查集问题,我们可以这样考虑,题目给定了 d d d条规定,每条规定 x x x y y y两点必联通,那么如果 x x x y y y不具有相同的祖宗节点,我们就将 x x x和y进行merge操作(即让它们的祖宗结点相同),如果 x x x y y y的祖宗结点已经相同,那么此时 x x x y y y之间的边就是一条闲边(因为 x x x y y y之间已经联通),闲边可以用来连接其他连通块,用 r e s res res来记录闲边的数量。然后我们遍历完所有的连通块,找出前 r e s res res+1 大的连通块相连( r e s res res条边可以连接 r e s res res+1个连通块)然后统计边数,输出答案。
  • 注意:连通块的大小要减1,因为度=大小-1.

代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e3+10;
int fa[N],size1[N],res=0;//fa[i]记录的是i的父节点,size[i]记录i这个点连通块中
                         //的大小 
int find(int x){
	if(fa[x]!=x) fa[x]=find(fa[x]);//迭代找祖宗节点 
	return fa[x];
}
void merge(int x,int y){//将两个集合合并 
	x=find(x),y=find(y);
	if(x==y) res++;//当两者的祖宗结点相同时,就可以多连出去一条边 
	else{
		fa[x]=y;
	    size1[y]+=size1[x];//将两个数祖宗结点变为一致,并合并联通块大小 
	}
}
int main(){
	int n,d;
	cin>>n>>d;
	for(int i=1;i<=n;i++){
		fa[i]=i;//初始每个数的父节点都是i 
		size1[i]=1;//初始每个数自己构成一个连通块 
	} 
	for(int i=1;i<=d;i++){
		vector<int> alls;
		int ans=0;//记录最大连通块的度 
		int x,y;
		cin>>x>>y;
		merge(x,y);
		for(int j=1;j<=n;j++){
			if(j==find(j)){
				alls.push_back(size1[j]);//如果j是祖宗结点,就将j的连通块大小加入
				                         //vector
			}
		}
		sort(alls.begin(),alls.end(),greater<int>());//将所有的连通块按从大到
		                                             //小的顺序排序 
		for(int j=0;j<alls.size() && j<=res;j++){
			ans+=alls[j];//取前res+1大的连通块 
		}
		ans--;//连通块的度等于大小-1 
		cout<<ans<<endl; 
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值