ZOJ原题链接: 传送门
Welcome Party
Time Limit: 2 Seconds Memory Limit: 131072 KB
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 participants of the World Finals, numbered from to 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 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 and are friends, and if participant and are friends, it's NOT necessary that participant and are friends.
Input
There are multiple test cases. The first line of the input contains a positive integer , indicating the number of cases. For each test case:
The first line contains two integers and (), the number of participants and the number of friendship relations.
The following lines each contains two integers and (), indicating that the -th and the -th participant are friends. Each friendship pair is only described once in the input.
It is guaranteed that neither the sum of nor the sum of of all cases will exceed .
Output
For each case, print a single integer on the first line, indicating the minimum number of unhappy participants. On the second line, print a permutation of to separated by a space, indicating the lexicographically smallest ordering of participants entering the hall that achieves this minimum number.
Consider two orderings and , we say is lexicographically smaller than , if there exists an integer (), such that holds for all , and .
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
题目大意
题目的意思是有一伙编号从1~n的参赛选手要通过一个入口进入场馆,给出m行数据,每行两个编号代表a和b是朋友,参赛选手需要排队一个一个进入场馆,每当一个人到达场馆,如果里面有他的朋友存在,那么他就会开心,否则不开心,注意,如果a和b是朋友b和c是朋友,那么a和c不一定是朋友,在确保不开心人数最少的情况下,使得参赛者的进入序列中小的编号尽可能排在前面,输出最少的不开心的人数和此时最小的排队序列
题目分析
这是一道对基础知识的考验比较全面的题目,解题主要用到了(并查集,优先队列,vector向量方面的知识),首先通过并查集的方法将输入的数据转化成一个一个的朋友集合,同时记录下每个集合编号最小的那个人一定是这个集合中最先去排队入场的人,牺牲你一个幸福全村人,他们的和就是不开心的人数。那么自然而然就需要一个能将这些必定要牺牲的人存放进去的容器(队列),而且可以每次取出编号最小的那个人,尽管都是要牺牲的,编号最小的还是要最先牺牲呀,那么优先队列的优势就体现出来了,每个放入的编号都能按我们的要求从小到大排序,这正是我们需要的。对于每个取出来去排队的人,我们要遍历与他直接相连的朋友的编号,如果没有加入到队列中,则加入,加入过了就跳过,这样做是因为有可能刚刚去排队的人有一位朋友他的编号比那些一定要牺牲的人编号还要小,那就先让他排进来,插到那些已经在队列中的人前面,反正他不会不开心,他的朋友这不刚刚进去了嘛,早点去排队正符合题意。那么我们此时就需要一个能记录一对多关系的容器,把每个人的朋友都和具体的每个人联系起来,vector正符合我们的需要。最后就是把不开心的人数输出,把排队的序列输出,over~
本题代码
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=1000005;
int vis[N];
int root[N];
int arr[N];
vector p[N];
int find(int x){
while(root[x]!=x) x=root[x];
return x;
}
void Union(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx, greater >q;
// while(!q.empty()) q.pop();
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++){ //初始化工作
root[i]=i;
vis[i]=0;
p[i].clear();
}
int x,y;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
Union(x,y); //并查集只是为了找出每个集合最小的点作为根节点,其连接方式并不重要
p[x].push_back(y); //此处要注意编号大的人可以拥有编号小的作为朋友
p[y].push_back(x); //编号小的也可以拥有编号大的作为朋友
}
int cnt=0;
for(int i=1;i<=n;i++){
if(root[i]==i){
q.push(i); //将每个集合编号最小的根放入队列
cnt++; //这些人包括那些没有任何朋友的人
}
}
int point=0;
while(!q.empty()){
int x=q.top();
q.pop();
if(vis[x]==0){//原先代码中没有判断这句话造成重复加点的情况产生
vis[x]=1;
arr[++point]=x;
for(int i=0;i