PAT_甲級_1107 Social Clusters

題目大意:

有N我的,若是任意2我的的愛好有相同的(就是有交集),那麼這2我的就是屬於同一個社交網絡,要求輸出這N我的組成了幾個社交網絡,而且輸出每一個社交網絡的人數算法

算法思路:

此題考察的是並查集的使用(並查集主要用來處理 若干個節點,有些節點互相相連,有些節點沒有鏈接,如何判斷其中兩個節點是否相連這樣的問題),目前來看,使用並查集求解此題應該是最好的選擇,能夠使用構建人與人的關係圖,而後遍歷有多少個連通份量,每個連通份量有多少節點,可是這種方式實現起來過於複雜。數組

並查集主要由1個集合,2個操做所組成,集合就是father保存每個節點的父節點,2個操做分別是查詢節點x的父親節點和合並2個節點所在的集合。入下面代碼所示:網絡

int father[1005];// 每個節點的父親節點

// 查詢節點x的父親節點
int findFather(int x){
    while(x!=father[x]){
        x = father[x];
    }
    return x;//father[x]==x的纔是根節點
}

// 合併a和b節點所在的集合
void Union(int a,int b){
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa!=fb){
        father[fa] = fb;
    }
}

在此題中,咱們須要構建一我的與人之間相互關聯的社交網絡,媒介是每個人所擁有的愛好,那麼咱們使用$hobbyOwner$記錄每個愛好的全部者,這樣在輸入每個愛好的時候,若是當前愛好沒有全部者,將當前愛好標記爲本身所獨有,不然就將該愛好全部者和當前人合併到一個社交網絡。在每個社交網絡構建完成後,咱們須要統計社交網絡的個數和每個社交網絡的人數,咱們使用$roots(set集合)$保存每個社交網絡的根節點,其個數即爲社交網絡的個數,$cluster$保存每個社交網絡的人數,具體作法就是,須要遍歷每個人,找到其根節點$root$,而後添加進$roots$中,而且統計當前社交網絡的人數++cluster[root]。最後對cluster進行排序輸出便可。測試

int cluster[1005];// 每個社交網絡的人數
unordered_set<int> roots;// 保存每個根節點

// 統計社交網絡的個數,也就是根節點的個數
for (int k = 1; k <= N; ++k) {
    int root = findFather(k);
    ++cluster[root];
    roots.insert(root);
}

注意點:

  • 一、有一種狀況須要特別注意,若是如今已經組建好了社交網絡A和B,那麼如今有一我的的愛好既有A又有B,那麼他將做爲鏈接A和B的橋樑,須要將每個人的全部愛好都要進行處理,而且因爲合併後,只更新了一個社交網絡的根節點的父親,該社交網絡的其餘節點的父親依然沒有變化,因此在統計社交網絡的人數的時候不能直接使用father數組,必定得重新遍歷每個節點獲取其父親,不然測試點1,4,5會錯誤。

提交結果:

image.png

AC代碼:

#include <cstdio>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>

using namespace std;

int father[1005];// 每個節點的父親節點
unordered_map<int,int> hobbyOwner;//每個愛好的全部者
int cluster[1005];// 每個社交網絡的人數

// 初始化每個節點的父親
void init(){
    for (int i = 1; i <= 1000; ++i) {
        father[i] = i;
    }
}

// 查詢節點x的父親節點
int findFather(int x){
    while(x!=father[x]){
        x = father[x];
    }
    return x;//father[x]==x的纔是根節點
}

// 合併a和b節點所在的集合
void Union(int a,int b){
    int fa = findFather(a);
    int fb = findFather(b);
    if(fa!=fb){
        father[fa] = fb;
    }
}

bool cmp(int a,int b){
    return a>b;
}

int main()
{
    init();
    int N;// 節點個數
    scanf("%d",&N);
    for (int i = 1; i <= N; ++i) {
        int K;
        scanf("%d: ",&K);
        for (int j = 0; j < K; ++j) {
            int hobby;
            scanf("%d",&hobby);
            if(hobbyOwner[hobby]==0){
                // 當前愛好沒有人擁有
                hobbyOwner[hobby] = i;
            } else {
                // 已經擁有了,合併擁有者和i
                Union(hobbyOwner[hobby],i);
            }
        }
    }
    unordered_set<int> roots;// 保存每個根節點
    // 統計社交網絡的個數,也就是根節點的個數
    for (int k = 1; k <= N; ++k) {
        int root = findFather(k);
        ++cluster[root];
        roots.insert(root);
    }
    printf("%lu\n",roots.size());
    sort(cluster+1,cluster+N+1,cmp);
    for(int i=1;i<=roots.size();++i){
        printf("%d",cluster[i]);
        if(i<roots.size()) printf(" ");
    }
    return 0;
}
相關文章
相關標籤/搜索