ZOJ4109-Welcome Party

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

题意:
给出n个人,用1~n标号。

m行表示m个关系,每行a,b表示a和b是朋友,朋友的关系不可传递。

如果一个人进场的时候场内没有自己认识的人则他会不开心,求一个合适的入场顺序使不开心的人数最少并且序列字典序最小。

解题思路:

用并查集可以找到总共有多少块,每块只有祖宗结点不开心。在合并的时候将merge()函数稍作修改,将块中的最小的那个数设为每一块的根结点。设置一个超级源点0将每一块的根结点都看作在同一块。使用bfs和优先队列遍历每个结点,能够拓展到的状态就是每个结点的朋友,出队列的顺序就是最小顺序。

首先每一个连通块肯定有一个人是不开心的,并且可以做到只有一个人是不开心的,所以有多少连通块,就有多少人不开心。对于字典序,只需要搞个优先队列遍历就可以了。然后因为有多个连通块,肯定不能一个块一个块的遍历,所以需要弄一个超级源点连到所有的起点上,然后再遍历,注意连到每个联通块的起点,这个起点需要是整个块的最小值,这样肯定使得结果最优。而让块的祖先节点是最小值,这一点可以用并查集稍作修改实现。

笔记:
1.判断有多少个集合,用并查集,Find到多少个根节点就有多少个集合,每次用Merge把连在一起的x和y的根节点合并。
2.每个集合起点要先取出来,然后才能取出来跟着这个起点的后续节点,用队列操作。先把所有起点放入队列,再枚举所有起点的后续节点放入队列,只有取出来起点的时候,才会把后续节点放进去,也就是说先取起点,才能取后续节点。
字典序用优先队列,每次放入队列都会自动从小到大排序。
3

priority_queue<int,vector<int>,greater<int> >pq;//从小到大排序,传入大于号
priority_queue<int,vector<int>,lessr<int> >pq;//从大到小排序,传入小于号,默认排序。

多组输入数据T,比如用scanf,不然会超时,这里用了多余的memset都超时了。。。ans每次自动从0~cnt更新,无需memset。memeset需谨慎!

5.优先队列自定义排序:

#include<cstdio>
#include<queue>
using namespace std;

struct node
{
    int x,y;
    //定义小于优先级
    bool operator < (const node &a)const
    {
        return x<a.x;//从大到小排序是<,从小到大排序是>
    }

}k;
priority_queue <node> q;
int main()
{
    k.x=10,k.y=100; q.push(k);
    k.x=12,k.y=60; q.push(k);
    k.x=14,k.y=40; q.push(k);
    k.x=6,k.y=80; q.push(k);
    k.x=8,k.y=20; q.push(k);
    while(!q.empty())
    {
        node m=q.top(); q.pop();
        printf("(%d,%d) ",m.x,m.y);
    }
}

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+10;
int T,sum,ans[maxn],cnt,n,m,fa[maxn],x,y,book[maxn];
vector<int>vec[maxn];
int Find(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=Find(fa[x]);
}
int Merge(int x,int y)
{
    int t1=Find(x);
    int t2=Find(y);
    if(t1<t2)
    {
        fa[t2]=t1;
    }
    else
    {
        fa[t1]=t2;
    }
}
void bfs()
{
    priority_queue<int,vector<int>,greater<int> >pq;
    pq.push(0);
    while(!pq.empty())
    {
        int now=pq.top();
        pq.pop();
        if(book[now]==0)
        {
            book[now]=1;
            ans[cnt++]=now;
            for(int i=0;i<vec[now].size();i++)
            {
                if(book[vec[now][i]]==0)
                {
                    pq.push(vec[now][i]);
                }
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        //memset(ans,0,sizeof(ans));
         sum=0;
         cnt=0;
         scanf("%d%d",&n,&m);
         for(int i=0;i<=n;i++)
         {
             vec[i].clear();
             fa[i]=i;
             book[i]=0;
         }
         for(int i=1;i<=m;i++)
         {
             scanf("%d%d",&x,&y);
             Merge(x,y);
             vec[x].push_back(y);
             vec[y].push_back(x);
         }
         for(int i=1;i<=n;i++)
         {
             if(fa[i]==i)
             {
                 sum++;
                 vec[0].push_back(i);
             }
         }
         bfs();
         cout <<sum << endl;
         for(int i=1;i<cnt;i++)
         {
            if(i==1)
                cout << ans[i];
            else
                cout << " " << ans[i];
         }
         cout << endl;
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/w1304636468/article/details/89811776