题目描述
一些科学家为森林中成千上万的鸟类拍照。
假设所有出现在同一张照片中的鸟都属于同一棵树。
请你帮助科学家计算森林中树木的最大数量,对于任何一对鸟类,请判断它们是否在同一棵树上。
输入格式
第一行包含整数 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;
}
感谢大佬,群里的大佬真多啊,哈哈,弱鸡的仰视
额 我就是那个说题解里面问问题不好的群友.