AtCoder abc231_d(或者说……UnionFind?)
最近在学数据结构,但是没找到我想要的题,真冤呀……手动滑稽
正在我苦恼的时候,我眼前出现了这样一道题:
这道题我是比赛后才做出来的……
于是!
U n i o n F i n d
手动滑稽
今天我就来给大家讲一讲UnionFind!
-------------------------------------------------------
UnionFind又称并查集。并查集最主要的功能就是“并”“查”!并查集主要就是一个“集”!并查集像是一棵树一样,但他是从下到上的(也就是说,可以很轻松的查找根,而不是叶子)!
-------------------------------------------------------
UnionFind的初版代码实现:
#include <bits/stdc++.h> using namespace std; class UnionFind { vector<int> root; // 集 public: UnionFind(int size) { root.push_back(0); for (int i = 1; i <= size; i++) { root.push_back(i); // 根节点是自己 } } public: bool Union(int number_a, int number_b) { // 并 int root_a = FindRoot(number_a); int root_b = FindRoot(number_b); return root[root_a] = root_b, root_a != root_b; // 不在同一组内就成功 } public: int FindRoot(int number) { // 查 if (root[number] == number) { return number; } return root[number] = FindRoot(root[number]); // 对于集合的优化 } };
有人可能就会问了,并查集和这题有什么关系?
关系可大了!如果合并不成功,不就出现环了吗?
#include <bits/stdc++.h> using namespace std; class UnionFind { vector<int> root; public: UnionFind(int size) { // 非常正常的构造 root.push_back(0); for (int i = 1; i <= size; i++) { root.push_back(i); } } private: int FindRoot(int number) { // 外面用不到FindRoot if (root[number] == number) { return number; } return root[number] = FindRoot(root[number]); } public: bool Union(int number_a, int number_b) { // 合并是否成功? int root_a = FindRoot(number_a); int root_b = FindRoot(number_b); return root[root_a] = root_b, root_a != root_b; } }; int main() { int n, m; scanf("%d%d", &n, &m); int a, b; UnionFind adjacent(n); int all[n + 5]; fill(all, all + n + 3, 0); for (int i = 1; i <= m; i++) { scanf("%d%d", &a, &b); if (!adjacent.Union(a, b)) { // 哎呀呀,形成环了! puts("No"); return 0; } all[a]++; // 还要统计 all[b]++; // 连接呢! } for (int i = 1; i <= n; i++) { if (all[i] > 2) { // 肯定不行的呀,你们说呢? puts("No"); return 0; } } puts("Yes"); // 经过了两道“检查”才能是Yes! return 0; }