ZOJ-4109 Welcome Party(並查集+BFS+優先隊列)

題目鏈接

題意:
有n個人要參加聚會,1~n分別表示他們的序列,m行表示他們之間的關係,這n個人一次進場,若進場後發現沒有自己的朋友,這個人就會不開心。現在要求排他們的入場順序,使得不開心的人數最少,同時,進場人的字典序最小。
思路:
由於他們的關係可以用聯通圖表示,則每一個聯通塊必然至少會有一個人不開心,所以用並查集判斷聯通塊個數。同時再用0號表示超級源點,依次將他們的朋友放進優先隊列中,出隊順序就是入場順序。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000050;
int  pre[MAXN],cnt;     //保存節點的直接父節點
vector<int>ve[MAXN];
int ans[MAXN],vis[MAXN];
//查找x的根節點
int Find(int x){
    if(pre[x]!=x)
        pre[x]=Find(pre[x]);//路徑壓縮,本結點更新爲根結點的子結點
    return pre[x];
}
//連接兩個連通塊
void join(int x,int y) {
    int fx=Find(x),fy=Find(y);
    if(fx>fy) pre[fx]=fy;
    else pre[fy]=fx;
}

void BFS(int x)
{
    priority_queue<int,vector<int>,greater<int> > q;
    q.push(x);
    while(!q.empty()){
        int now = q.top();q.pop();
        if(!vis[now]){
            vis[now]=1;
            ans[cnt++]=now;	//出隊順序是入場順序
            for(int i=0;i<ve[now].size();i++){
                if(!vis[ve[now][i]]){
                    q.push(ve[now][i]);
                }
            }
        }
    }
}

int main() {
    int T;
    cin>>T;
    while(T--){
        int N,M,a,b,i,j,ans1=0;
        scanf("%d%d",&N,&M);
        //初始化pre數組
        for(i=0;i<=N;i++){
            pre[i]=i;//根據連通情況,構建pre數組
            vis[i]=0;
            ve[i].clear();
        }
        for(i=1;i<=M;i++) {
            scanf("%d%d",&a,&b);
            ve[a].push_back(b);
            ve[b].push_back(a);
            join(a,b);
        }
        for(i=1;i<=N;i++){
            if(pre[i]==i){
                ans1++; //計算連通子圖的個數ans
                ve[0].push_back(i);
            }
        }
        cnt=0;
        BFS(0);
        cout<<ans1<<endl;
        for(int i=1;i<cnt;i++){
            if(i==1)    printf("%d",ans[i]);
            else printf(" %d",ans[i]);
        }printf("\n");
    }
    return 0;
}

發佈了48 篇原創文章 · 獲贊 2 · 訪問量 3034
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章