题意:给定一些照片,照片上面有一些树,树上有一些小鸟,判断最大的数的颗树可能有多少棵以及鸟有多少只;
思路:此题主要考察并查集,用一个数组保存信息,下标为节点的数据,值为节点的父节点,用一个访问数组标识该节点是否遍历到过,用于计算多少只,最后数组中访问过的节点而且值为负表示为根节点,根节点有多少个表示数就有多少棵;
如果并查集的概念不是很清楚的,建议先去看看并查集的概念,推荐看姥姥的mooc视频,此题涉及到了姥姥说的一些问题以及一些解决的方法,比如数的高度一直长高的问题如何解决,以及对如何加快对根节点的查找效率等问题;
代码:
#include<iostream>
#include<algorithm>
using namespace std;
int s[10010];
bool vis[10010] = {false};
int find(int x){
if (s[x] < 0)return x;
else {
return s[x] = find(s[x]);//路径压缩,返回值的时候顺便更新所有的路径上的根节点
}
}
void Union(int id1,int id2) {
int root1 = find(id1);//当并的时候检查两个时候已经属于一个集合,不属于一个集合就合并两个节点
int root2 = find(id2);
if (root1 != root2) {//当两个根节点的不相同的时候,就进行合并
if (s[root2] < s[root1]) {//第二个子树规模比第一个大,根节点的值为负表示无父节点,绝对值为以该节点为根节点的树的节点个数
s[root2] += s[root1];
s[root1] = root2;//把节点个数少的并到节点个数大的数中去
}else {
s[root1] += s[root2];
s[root2] = root1;
}
}
}
int main() {
fill(s, s + 10010, -1);//首先初始化,默认所有的节点认为自己是根节点
int n, k, first, tem, quiry, maxtree = 0, maxbirds = 0,id1, id2;;
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d%d",&k,&first);
if (vis[first] == false)vis[first] = true;
for (int j = 0; j < k - 1; j++) {
scanf("%d",&tem);
if (vis[tem] == false)vis[tem] = true;
Union(first,tem);
}
}
cin >> quiry;
for (int i = 1; i<=10010; i++) {//查找所有的树和鸟,图片中的鸟的个数可能超过了总的鸟的数目要限制
if (vis[i] == true) {
maxbirds++;
if (s[i] < 0)maxtree++;
}
}
cout << maxtree << " " << maxbirds << endl;
for (int i = 0; i < quiry; i++) {
scanf("%d%d",&id1,&id2);
printf("%s\n", find(id1)== find(id2)?"Yes":"No");
}
system("pause");
return 0;
}