C++ 并查集模板
并查集一般在遇到求解冗余關系,關系合并,環的數量等問題的時候使用。不需要對各數值進行輸出。
注意與有向無環圖問題進行區分!
有向無環圖模板看這里:有向無環圖講解及模板(C++代碼)_子木呀的博客-CSDN博客_c++ 有向無環圖
并查集是一個很優美的數據結構,很多情況下,提煉問題后,可以用并查集進行解決,這里總結下并查集的模板及注釋,可以直接用
1.并查集的使用:
//初始化并查集 int n = xx.size(); UnionFindSet dsu(n);//初始化并查集//將兩個點合并 for(int i = 0; i < n; i++){dsu.merge(xx[i], xx[i])//...... }2.并查集模板(直接用就行,可以根據需要修改返回值出代碼)?
有兩處優化:(1)查詢優化 (2)路徑優化
//并查集實現 class UnionFindSet{vector<int> F;//并查集容器vector<int> rank;//秩優化(如果兩個都有很多元素的根節點相遇,將根節點選為元素較少的那一個,可以節省時間)int n;public://并查集初始化UnionFindSet(int _n){n = _n;F.resize(n);rank.resize(n, 1);for(int i = 0; i < n; i++){F[i] = i;}}//并查集查詢操作int find(int x){return x == F[x] ? x : F[x] = find(F[x]);//查詢優化。找到x的根節點}//并查集合并操作bool merge(int x, int y){int fx = find(x), fy = find(y);if(fx == fy) return false;//兩個節點連在同一個根節點上則直接返回 不再合并//因為是將節點數少的連接到節點數多的節點上,當fx下面的節點數小于fy下面的節點數時,交換fx和fy//即兩個根節點相遇時,將新的根節點選為節點數較多的那一個,盡量減少find(x)的次數if(rank[fx] < rank[fy])//合并優化swap(fx, fy);F[fy] = fx;//將fy連到fx上(將節點數少的連接到節點數多的上面)rank[fx] += rank[fy];//將fy連到fx后 fx下面的節點數目要更新return true;} };結合輸入的方式,不使用類。完全可以用的一個示例:
#include <iostream> #include<vector> #include<string> #include <unordered_map> #include <unordered_set> #include <queue> #include <algorithm>//算法頭文件 #include <numeric> #include <stack> #include<typeinfo> using namespace std;vector<int> F; // 初始化 void UnionFindSet(int N) {F.resize(N + 1, -1);//如果初始化是從1開始,這里就得用N+1 如果從0開始初始化 就用N(從多少開始初始化 根據輸入的數據進行調整)for (int i = 1; i <= N; i++){F[i] = i; // 初始化時, 將自己初始化為自己的領導} }// 查找 int find(int n) {return n == F[n] ? n : find(F[n]); }// 合并 這里直接在主程序里調用了查找 能夠省去調用合并函數的次數 void merge(int leaderX, int leaderY) {if (leaderX < leaderY){F[leaderX] = leaderY;}else{F[leaderY] = leaderX;} }// 輸入數組, 每一行表示一個集合關系, 比如第一行表示3和4屬于一個集合 int input[] = {1, 4,2, 5,3, 6,4, 2,5, 1,6, 3, };int main() {int N;cin >> N;int numberOfSets = N;// 初始化領導UnionFindSet(N);int n = sizeof(input) / sizeof(input[0]) / 2;//這地方根據輸入的形式調整int j = 0;for (int i = 0; i < n; i++){int u = input[j++];int v = input[j++];u = find(u);//這里直接在主程序里調用了查找 能夠省去調用合并函數的次數v = find(v);if (u != v) { //如果沒關系 就合并 最后numberOfSets就是不能合并的個數 也就是有幾個圈子merge(u, v);numberOfSets--;}}cout << numberOfSets << endl;return 0; }統計某個節點下掛了多少個節點
#include <iostream> #include<vector> #include<string> #include <unordered_map> #include <unordered_set> #include <queue> #include <algorithm>//算法頭文件 #include <numeric> #include <stack> #include<typeinfo> using namespace std; vector<int> F; // 初始化 void UnionFindSet(int N) {F.resize(N + 1, -1);//如果初始化是從1開始,這里就得用N+1 如果從0開始初始化 就用N(從多少開始初始化 根據輸入的數據進行調整)for (int i = 1; i <= N; i++){F[i] = i; // 初始化時, 將自己初始化為自己的領導} }// 查找 int find(int n) {return n == F[n] ? n : find(F[n]); }int main() {int N, M;cin >> N >> M;vector<vector<int>> input;vector<int> intput1;int a,b;for (int i = 0; i < M; i++) {cin >> a >> b;intput1.push_back(a);intput1.push_back(b);input.push_back(intput1);}// 初始化領導UnionFindSet(N);for (int i = 0; i < M; i++){int u = input[i][0];int v = input[i][1];u = find(u);//這里直接在主程序里調用了查找 能夠省去調用合并函數的次數v = find(v);if (u != v) { //如果沒關系 就合并 最后numberOfSets就是不能合并的個數 也就是有幾個圈子F[v] = u;}}int numberOfSets = 0;for (int i = 0; i < F.size(); i++) {if (F[i] == 1)numberOfSets++;}cout << numberOfSets+1 << endl;return 0; }總結
- 上一篇: 数学建模酶促反应matlab求解,数学建
- 下一篇: linux 监听日志_Linux系统取证