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

题意:T组数据,n个人,m个关系,接下来m行,每行给定一对朋友关系,朋友关系不具有传递性。接下来n个人要进入一个会场,当一个人进入会场时如果发现他的所有朋友都没有进入会场,这时他会很生气。问怎样安排这些人的进入顺序才能使得生气的人数最少。输出最少的生气人数,以及进入顺序(字典序最小)。

思路:虽然关系不具有传递性,但想要生气人数最少还是一个集合一个集合来的,所以求最少的生气人数只需要并查集求多少集合就好了。关键在于顺序怎样选择。对于一个集合来说,我们让这个集合的最小值作为祖先。然后我们将所有的祖先入优先队列,接下来依次取队首,这个就是当前最优解,然后将他能到达的点也加入到优先队列中。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<iostream>
#define inf 0x3f3f3f3f
#define ll long long
#define N 1000010
using namespace std;

int n,a[N],f[N],book[N];
vector<int>v[N];
struct node
{
    int x;
    bool operator < (const node &aa)const
    {
        return aa.x<x;
    }
    node(int i=0)
    {
        x=i;
    }
};
priority_queue<node>Q;
void init()
{
    while(!Q.empty())
        Q.pop();
    for(int i=1; i<=n; i++)
    {
        f[i]=i;
        book[i]=0;
        v[i].clear();
    }
}
int getf(int x)
{
    if(x==f[x])return x;
    return f[x]=getf(f[x]);
}
void merge(int x,int y)
{
    int t1=getf(x);
    int t2=getf(y);
    if(t1<t2)f[t2]=t1;
    else f[t1]=t2;
}
vector<int>u;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m;
        u.clear();
        scanf("%d%d",&n,&m);
        init();
        int cnt=0;
        for(int i=1; i<=m; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            merge(x,y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        for(int i=1; i<=n; i++)
            if(getf(i)==i)
            {
                cnt++;
                u.push_back(i);
            }

        for(int i=0; i<u.size(); i++)
        {
            int x=u[i];
            Q.push(node(x));
            book[x]=1;
        }
        m=1;
        while(!Q.empty())
        {
            node p=Q.top();
            Q.pop();
            a[m++]=p.x;
            for(int j=0; j<v[p.x].size(); j++)
            {
                int y=v[p.x][j];
                if(!book[y])
                {
                    book[y]=1;
                    Q.push(node(y));
                }
            }
        }
        printf("%d\n",cnt);
        for(int i=1; i<=n; i++)
        {
            if(i<n)printf("%d ",a[i]);
            else printf("%d\n",a[i]);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值