Welcome Party(并查集+优先队列+邻接表)

Welcome Party

The 44th World Finals of the International Collegiate Programming Contest (ICPC 2020) will be held in Moscow, Russia. To celebrate this annual event for the best competitive programmers around the world, it is decided to host a welcome party for all nn participants of the World Finals, numbered from 11 to nn for convenience.

The party will be held in a large hall. For security reasons, all participants must present their badge to the staff and pass a security check in order to be admitted into the hall. Due to the lack of equipment to perform the security check, it is decided to open only one entrance to the hall, and therefore only one person can enter the hall at a time.

Some participants are friends with each other. There are mm pairs of mutual friendship relations. Needless to say, parties are more fun with friends. When a participant enters the hall, if he or she finds that none of his or her friends is in the hall, then that participant will be unhappy, even if his or her friends will be in the hall later. So, one big problem for the organizer is the order according to which participants enter the hall, as this will determine the number of unhappy participants. You are asked to find an order that minimizes the number of unhappy participants. Because participants with smaller numbers are more important (for example the ICPC director may get the number 1), if there are multiple such orders, you need to find the lexicographically smallest one, so that important participants enter the hall first.

Please note that if participant aa and bb are friends, and if participant bb and cc are friends, it’s NOT necessary that participant aa and cc are friends.

Input
There are multiple test cases. The first line of the input contains a positive integer TT, indicating the number of cases. For each test case:
The first line contains two integers nn and mm (1 \le n,m \le 10^61≤n,m≤10
6 ), the number of participants and the number of friendship relations.
The following mm lines each contains two integers aa and bb (1 \le a,b \le n, a \neq b1≤a,b≤n,a =b), indicating that the aa-th and the bb-th participant are friends. Each friendship pair is only described once in the input.It is guaranteed that neither the sum of nn nor the sum of mm of all cases will exceed 10^6
output
Foreach case,print a single integer on the first line, indicating the minimum number of unhappy
participants.On the second line,print a permutation of 1 to n separated by a space, indicating the
lexicographically smallest ordering of participants entering the hall that achieves this minimum
number.
Consider two orderingsP= p1,p2,….,pn andQ= q1,2,… qn,we say Pis lexicographically smaller than Q, if there exists an integer k(1<k<n), such that p= q holds for all1<i<k, and pk<qk. Please, DO NOT output extra spaces at the end of each line,or your solution may be considered
incorrect!

Sample Input
2
4 3
1 2
1 3
1 4
4 2
1 2
3 4
Sample Output
1
1 2 3 4
2
1 2 3 4

思路

  • 其实输出的第一个答案就是树的多少,一个朋友圈中,编号最小的就是根节点,然后按顺序输出相对应的叶子节点。
  • 因此直接建树,用并查集和合并(要添加一个判断,优先将小的作为根节点)创建树。
  • 然后遍历树,将节点分别加入优先队列,存储答案
  • 最后输出数组中的答案。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e6+7;

int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){ if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return f*x;
}
int cnt,vis[MAXN],fa[MAXN];
// 并查集
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
// 合并树的根节点
void mer(int a,int b){
	int aa=find(a);
	int bb=find(b);
	// 判断,小的那个成为根节点
	if(aa>bb)fa[aa]=bb;
	else fa[bb]=aa;
}

vector<int> v[MAXN];
int n,m,ans[MAXN];
// bfs 找树
void bfs(int x){
	priority_queue<int,vector<int> ,greater<int> > q;
	cnt = 0;
	q.push(x);
	while(!q.empty()){
		int u=q.top();
		q.pop();
		if(vis[u]) continue;
		ans[cnt++]=u;
		vis[u]=1;
		for(int i=0;i<v[u].size();i++){
			if(!vis[v[u][i]])q.push(v[u][i]);
		}
	}
	return ;
}
int t;
int main(){
	cin >> t;
	while(t--){

		n=read(),m=read();
		for(int i=0;i<=n;i++)fa[i]=i,v[i].clear(),vis[i]=0;
		for(int i=1,a,b;i<=m;i++){
			a=read(),b=read();
			// 邻接表存树
			v[a].push_back(b);
			v[b].push_back(a);
			mer(a,b);
		}
		int sum=0;
		// 储存相对应的根节点
		for(int i=1;i<=n;i++){
			if(fa[i]==i)sum++,v[0].push_back(i);
		}
		bfs(0);
		printf("%d\n",sum);
		for(int i=1;i<cnt-1;i++){
			printf("%d ",ans[i]);
		}
		printf("%d\n",ans[cnt-1]);
		}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杂货店的阿猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值