地址 https://www.acwing.com/solution/content/15062/
一些科学家为森林中成千上万的鸟类拍照。 假设所有出现在同一张照片中的鸟都属于同一棵树。 请你帮助科学家计算森林中树木的最大数量,对于任何一对鸟类,请判断它们是否在同一棵树上。 输入格式 第一行包含整数 N 表示照片数量。 接下来 N 行,每行描述一张照片,格式如下: K B1 B2 … BK K 表示照片中的鸟的数量,Bi 是鸟的具体编号。 保证所有照片中的鸟被连续编号为 1 到某个不超过 104 的整数。 再一行包含整数 Q。 接下来 Q 行,每行包含两个鸟的编号,表示一组询问。 输出格式 第一行输出最大可能的树的数量以及鸟的数量。 接下来对于每个询问,如果被询问的两个鸟在同一棵树上,则在一行中输出 Yes,否则输出 No。 数据范围 1≤N≤104, 1≤K≤10, 1≤Q≤104 输入样例: 4 3 10 1 2 2 3 4 4 1 5 7 8 3 9 6 4 2 10 5 3 7 输出样例: 2 10 Yes No
算法1
并查集裸题
考察对并查集原理和操作。
询问完所有数据后,在一棵树上的鸟的编号可以使用并查集合并。
鸟的编号是1~n,那么输入的最大编号就是鸟的数目
树的数目其实就是1~n中并查集的种类
根据并查集的定义,f[1]~f[n]中 f[i]!=i 就说明他和别人在同一个并查集里
那么我们只要统计 f[i]==i的个数 就是并查集的集合数目也就是题目中树的数目
C++ 代码
#include <iostream> #include <vector> #include <algorithm> using namespace std; const int N = 10010; int f[N]; int cnt[N]; void init() { for (int i = 1; i < N; i++) { f[i] = i; cnt[i] = 1; } } int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); } int n, m; vector<int> v[N]; int uni[N]; int maxNum = -1; int main() { cin >> n; init(); for (int i = 0; i < n; i++) { int num = 0; cin >> num; for (int j = 0; j < num; j++) { int t;cin >> t; maxNum = max(t, maxNum); v[i].push_back(t); } for (int j = 0; j < v[i].size() - 1; j++) { int a = v[i][j]; int b = v[i][j + 1]; a = find(a); b = find(b); if (a != b) { f[a] = b; cnt[b] += cnt[a]; } } } int ans = 0; for (int i = 1; i <= maxNum; i++) { int idx = find(i); uni[idx]++; } for (int i = 1; i <= maxNum; i++) { if (uni[i] != 0) ans++; } cout << ans << " "<< maxNum << endl; cin >> m; for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; if (find(a) == find(b)) { cout << "Yes" << endl; } else { cout << "No" << endl; } } return 0; }