题目描述
一些科学家拍摄了森林中数千只鸟的照片。假设出现在同一张图片中的所有鸟都属于同一棵树。你应该帮助科学家计算森林中树木的最大数量,对于任何一对鸟,判断它们是否在同一棵树上
解题思路
包括合并和查找操作
代码
#include<bits/stdc++.h>
using namespace std;
int numPicture, numBird, numQuery;
vector<int> idBird;
map< int, set<int> > myMap;//树作为键,鸟作为值
int main() {
map<int, set<int> >::iterator iter;
cin >> numPicture;
for (int i = 0; i < numPicture; i++) {
cin >> numBird;
bool flag = false;
idBird.clear();
//对每一幅图像操作 1. 录入鸟儿的信息
for (int j = 0; j < numBird; j++) {
int tem;
cin >> tem;
idBird.push_back(tem);
}
//判断是否可以合并树
for (int j = 0; j < idBird.size(); j++) {
for (iter = myMap.begin(); iter != myMap.end(); iter++) {
if (iter->second.find(idBird[j]) != iter->second.end()) {//找到了这只鸟
flag = true;
break;
}
}
if (flag == true)
break;
}
//这只鸟存在于别的树上 iter
if (flag == true) {
for (int j = 0; j < idBird.size(); j++) {
//如果找到了相应的函数
iter->second.emplace(idBird[j]);
}
}
else {//这只鸟自己为一棵树
set<int> se;
for (int j = 0; j < idBird.size(); j++) {
se.emplace(idBird[j]);
}
myMap.emplace(myMap.size() + 1, se);
}
}
//TODO: 1
int numB = 0;
for (iter = myMap.begin(); iter != myMap.end(); iter++) {
numB += iter->second.size();
}
cout << myMap.size() << ' ' << numB << endl;
//TODO: 2
cin >> numQuery;
int bird1, bird2;
for (int i = 0; i < numQuery; i++) {
cin >> bird1 >> bird2;
for (iter = myMap.begin(); iter != myMap.end(); iter++) {
if (iter->second.find(bird1) != iter->second.end()) {//找到了第一只鸟
if (iter->second.find(bird2) != iter->second.end())
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
}
return 0;
}
使用并查集
代码
#include<bits/stdc++.h>
using namespace std;
int n, birdNum, birdId, sumBird = 0;
vector<bool> flag(10010);
vector<int> father(10010);
void init(int n) {//初始化并查集地两个集合
flag.resize(n + 10);
father.resize(n + 10);
//对每一个表示是否是根地址的数组设置为true,父亲节点都指向自己
for (int i = 0; i < n; i++) {
flag[i] = true;
father[i] = i;
}
}
int findFather(int x) {//寻找本集合的父亲节点
int a = x;
//下标表示数据,属性值表示父亲节点
while (father[x] != x) {
x = father[x];
}
//新增路径压缩,目的是为了解决极端情况下查找根结点效率低下的问题
while (father[a] != a) {
int b = a;//防止修改
a = father[a];
father[b] = x;//所有的节点的父节点全部设置为根结点
}
return x;
}
void unionSet(int x, int y) {//合并两个集合
int rootX = findFather(x);
int rootY = findFather(y);
if (rootX != rootY) {
//属于不同的集合,此时进行合并操作
father[rootY] = rootX;
flag[rootY] = false;//删除根结点,此时flag置为false
}
}
int main() {
cin >> n;//图片的个数
init(10000);
//读取每一张图片上的小鸟
for (int i = 0; i < n; i++) {
cin >> birdNum;
cin >> birdId;
sumBird = max(sumBird, birdId);
for (int j = 1; j < birdNum; j++) {
int tem;
cin >> tem;
sumBird = max(sumBird, tem);
unionSet(birdId, tem);
}
}
int numQuery, x, y, sum = 0;
cin >> numQuery;
for (int i = 0; i < sumBird; i++) {
if (flag[i] == true) {
sum++;
}
}
cout << sum << ' ' << sumBird << endl;
for (int i = 0; i < numQuery; i++) {
cin >> x >> y;
x = findFather(x);
y = findFather(y);
if (x == y) {
cout << "Yes" << endl;
}
else {
cout << "No" << endl;
}
}
return 0;
}