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;
}