標籤:並查集
題目描述:
假如已知有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、m,1=<n,m<=100000。接下來有m行,每行分別輸入兩個人的編號f,t(1=<f,t<=n),表示f和t是好友。 當n為0時,輸入結束,該用例不被處理。
輸出:
對應每個測試案例,輸出在這n個人裡一共有多少個朋友圈。
範例輸入:
5 3
1 2
2 3
4 5
3 3
1 2
1 3
2 3
0
範例輸出:
2
1
解題思路
使用由多棵樹組成的森林來解題,每棵樹代表一個朋友圈。構建兩個數組id和sz,id[x]表示x的根節點,sz[x]表示以x為根節點的樹的結點個數。
- 初始化:for i = 1 to personCount, id[i] = i, sz[i] = 1;
- 判斷輸入的一組關係,看兩個結點是否位於同一棵樹(根節點是否相同),如果不同,則將較小的樹合并到較大的樹(將小數根節點的根節點設為大樹的根節點),同時將大樹的結點個數設定為大樹結點與小樹結點之和。
(對於尋找函數,為了加快查詢速度,可以對路徑進行壓縮,即將結點的父節點設定為它的祖父結點)
更詳細思路:http://blog.csdn.net/dm_vincent/article/details/7655764
實現代碼
#include <iostream>using namespace std;class UF{public: UF(int n) { id = new int[n]; sz = new int[n]; count = n - 1; for (int i = 0; i < n; i++) { id[i] = i; sz[i] = 1; } } int getCount() { return count; } int findSet(int n) { while (n != id[n]) { id[n] = id[id[n]]; n = id[n]; } return n; } void unionSet(int x, int y) { int dx = findSet(x); int dy = findSet(y); if (dx != dy) { count--; if (sz[dx] > sz[dy]) { id[dy] = dx; sz[dx] += sz[dy]; } else { id[dx] = dy; sz[dy] += sz[dx]; } } } ~UF() { delete [] id; delete [] sz; }private: int *id; int *sz; int count;};int main(){ int personCount; while (cin>>personCount, personCount) { UF *uf = new UF(personCount + 1); int relationCount; cin>>relationCount; int x, y; for (int i = 0; i < relationCount; i++) { cin>>x>>y; uf->unionSet(x, y); } cout<<uf->getCount()<<endl; delete uf; } return 0;}
[小米] 並查集