本篇博文旨在介紹一種資料結構——並查集;本文介紹了該資料結構的使用場景,並用**進行了實現該資料結構
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...