先來看一下題目:
已知有n個人和m個好友關係(存在數字r),如果兩個人是直接或者間接的好友(好友的好友的好友……),則認爲他們屬於同一個朋友圈。請寫程序求出這n個人裏一共有多少個朋友圈?
例如:n=5,m=3,r={{1,2},{2,3},{4,5}},表示有5個人,1和2是好友,2和3是好友,4和5是好友,則1、2、3屬於一個朋友圈,4、5屬於一個朋友圈。最終結果就是2個朋友圈
爲了追求高效且準確,我們用到了並查集來完成這道題
一、並查集?
並查集就是將n個不同的元素劃分成爲一組不相交的集合。開始時,每個元素自成一個單元素集合,然後按照一定的規律將歸於同一組元素的集合合併。
它是一種樹形的數據結構,每個集合以一棵樹表示,樹的每一個結點代表集合的一個單元素。所有各個集合的全集合構成一個森林,並用樹與森林的父指針表示來實現。其下標代表元素名。第i個數組元素代表集合元素i的樹結點。樹的根結點的下標表示集合名稱,根結點的父爲-1,表示集合中元素個數
二、圖示表示一下
以上面的題的爲基礎爲例:
n=5,m=3,r={{1,2},{2,3},{4,5}},表示有5個人,1和2是好友,2和3是好友,4和5是好友,則1、2、3屬於一個朋友圈,4、5屬於一個朋友圈。最終結果就是2個朋友圈
集合爲:r={1,2,3,4,5}
開始時,每個元素就是一個集合
按照上面所給的要求將集合中的元素合併成爲三個子集合
r1 = {1,2}
r2 = {2,3}
r3 = {4,5}
用樹狀來表示所形成的朋友圈就是:
與此同時,我們將好友關係用數組的方式來記錄,因爲2是1的朋友,所有就將2的下標疊加到1的下面去,2下標下的數據也存放在的1的下面。3是2的朋友,2是1的朋友,所以就把3的下標疊加到1的下面去,3下標下的數據也存放在的1的下面。4和5的朋友圈如同上述
在同一棵樹上的所有節點所表示的集合元素在同一個子集合中。對於任意給定的集合元素x,只要藉助這個映射就能找到存放x的樹結點,沿此存放x結點的父指針向上一直走到樹的根結點,就可以得到x所在集合的名字。
總結:
* (1)只要某一個下標裏的數據爲負數,則它就是其所在朋友圈的根。負數的大小表示着朋友圈的人數(eg:下標1中的數據爲-3,則其所在的朋友圈人數爲3)
* (2)數組中有幾個負數就表示有幾個朋友圈
* (3)可以根據下標中所對應的數字找到根節點,相同根節點的就在同一個朋友圈內
下面來看看代碼實現:
#include <iostream>
using namespace std;
#include <vector>
class UnionFriend
{
public:
// 構造函數(用-1初始化)
UnionFriend(int size)
:_set(size, -1)
{
// 其他方式
// _set.resize(size, -1)
// _set.assign(size, -1)
}
// 求交集
void Union(int x1, int x2)
{
// 先找x1、x2的根
int root1 = FindRoot(x1);
int root2 = FindRoot(x2);
//比較x1和x2的根是否相等
if (root1 != root2)
{
_set[root1] += _set[root2];
_set[root2] = root1;
}
}
// 求合併後集合的個數
size_t count()
{
size_t count = 0;
//統計負數的個數
for (size_t i = 0; i < _set.size(); i++)
{
if (_set[i] < 0)
{
count++;
}
}
return count;
}
private:
//查找根節點
int FindRoot(int index)
{
while (_set[index] >= 0)
{
index = _set[index];
}
return index;
}
private:
//一段連續的空間
std::vector<int> _set;
};
int friends(const int m, const int n, int r[][2])
{
//讓下標從1開始,符合題目
UnionFriend u(m + 1);
for (int i = 0; i < n; i++)
{
u.Union(r[i][0], r[i][1]);
}
return u.count() - 1;
}
void Test()
{
int r[][2] = { {1,2},{2,3},{4,5} };
cout << "朋友圈個數:" << friends(5, 3, r) << endl;
}
int main()
{
Test();
system("pause");
return 0;
}