資料結構 朋友圈問題的解決 並查集

2021-07-27 23:12:52 字數 2158 閱讀 9079

本篇博文旨在介紹一種資料結構——並查集;本文介紹了該資料結構的使用場景,並用**進行了實現該資料結構

1、已知,有n個人和m對好友關係(存於乙個集合r中)

2、如果兩個人是直接的或者間接的好友(好友的好友的好友。。。),那麼他們屬於乙個集合,就是乙個朋友圈裡的

3、寫出程式,求這n個人中一共有多少個朋友圈

文字描述還不明白的童鞋,可以看下面這個例子

例如:n = 5 m = 3   

r = ,, }

五個人有三對朋友關係

根據 集合r  我們可以看出1 、 2 、3 屬於乙個朋友圈,4和5屬於乙個朋友圈

所以結果有兩個朋友圈

由於之前學習過雜湊表

所以就想出了這樣的解法

建立乙個長度為n+1的陣列(可以利用vector)

對應下標代表的是該人

然後遍歷一遍 集合r  比如(1,2)就將2掛到1節點的後面

最後我們遍歷一遍該陣列,從1鏈結的節點中找到2,然後去找下標為2的陣列鏈結的數字3,再找3,然後3沒有鏈結節點,則表示是乙個朋友圈

依次輪推,可以算出兩個朋友圈

這個方法的確可行

但是,當關係量稍微複雜點就不好使了

其實7個人同屬於乙個朋友圈,但是1-2結束,就多算乙個朋友圈

而且,由於處理不當還出現了迴圈的問題,比如1-2-3-1

當然,這種情況可以通過加以處理來避免

但是這樣也太複雜了

有沒有一種簡便的方法來處理這個問題呢?

這裡引入這次要介紹的資料結構——並查集

將n個不同的元素分成互不相交的集合

然後按照規律將兩個集合進行合併

1、首先我們建立n個大小的陣列,分別代表人的序號

將陣列的所有值初始化為 -1 ,代表各自屬於各自的集合

2、根據 集合r 對陣列元素的值進行修改

比如 將a[0] 的值加上 a[6]的值

然後將a[6]所存的值改為 a[0]的下標 0 

修改後的下標如下圖所示

下面,如果0和4產生了關係,

那麼找到4的根(為1),將a[1]的值加到a[0]上,然後將a[1]的值改為a[0]的下標0

通過對陣列元素的遍歷,只要值小於0,即代表為乙個集合(朋友圈)中

#pragma once

#includeusing namespace std;

#include//定義並查集

class unionfindset

//找到根節點

size_t findroot(size_t x)

//將兩個人的朋友圈進行合併

void union(size_t x1,size_t x2)

//判斷是否在乙個集合

bool isinset(int x1, int x2)

//求集合(朋友圈)的個數

size_t setsize()

return count-1;

}protected:

vectorv;

};void testunionfindset()

, , , };

for (size_t i = 0; i < m; ++i)

cout << "朋友圈的個數為:" << ufs.setsize() << endl;

}

資料結構 並查集 解決朋友圈問題

首先我們先來看乙個栗子 朋友圈問題 1 已知,有n個人和m對好友關係 存於乙個集合r中 2 如果兩個人是直接的或者間接的好友 好友的好友的好友。那麼他們屬於乙個集合,就是乙個朋友圈裡的。3 寫出程式,求這n個人中一共有多少個朋友圈。例如 n 5,m 3 r 因為集合和集合中有共同的朋友2,所以1,2...

PAT 朋友圈(並查集)

某學校有n個學生,形成m個俱樂部。每個俱樂部裡的學生有著一定相似的興趣愛好,形成乙個朋友圈。乙個學生可以同時屬於若干個不同的俱樂部。根據 我的朋友的朋友也是我的朋友 這個推論可以得出,如果a和b是朋友,且b和c是朋友,則a和c也是朋友。請編寫程式計算最大朋友圈中有多少人。輸入的第一行包含兩個正整數n...

5 9 朋友圈 (並查集)

某學校有n個學生,形成m個俱樂部。每個俱樂部裡的學生有著一定相似的興趣愛好,形成乙個朋友圈。乙個學生可以同時屬於若干個不同的俱樂部。根據 我的朋友的朋友也是我的朋友 這個推論可以得出,如果a和b是朋友,且b和c是朋友,則a和c也是朋友。請編寫程式計算最大朋友圈中有多少人。輸入的第一行包含兩個正整數n...