题目
一幅画里面的鸟为同一棵树上的,问有多少棵树和多少只鸟,以及对于两只鸟判断是否在同一个树上~
输入第一行为N,接下来有N行
这N行中,第一个是这幅画(这棵树)里面的鸟的数量K,接下来是这K个鸟的编号。输出有多少棵树,多少只鸟。
接着,输入Q,表示询问的个数。
接下来的Q行,有两个鸟的编号,问你这两个鸟是不是在同一幅画(一棵树)中。
分析
躺尸很多天。。。
并查集选择使用了递归写法。
int ffind(int a)
{
if( a != pre[a])
{
pre[a] = ffind(pre[a]);
}
return pre[a];
}
但是要注意这种写法中,
if(exist[i]) //cout << i << " " << pre[i] << endl;
{
int root = ffind(i);
cnt[root] ++;
//cout << i << " " << root << endl;
}
这两个地方cout的结果是不同的。递归写法需要再一次压缩路径。
代码
const int maxn = 1e4 + 10;
int pre[maxn];
int exist[maxn];
int cnt[maxn];
int ffind(int a)
{
if( a != pre[a])
{
pre[a] = ffind(pre[a]);
}
return pre[a];
}
int main()
{
for(int i = 0 ; i < maxn ; i ++)
pre[i] = i;
int N ; cin >> N;
for(int i = 0 ; i < N ; i ++)
{
int K ; cin >> K;
int st ; cin >> st; exist[st] = 1;
for(int i = 0 ; i < K - 1 ; i ++)
{
int ed ; cin >> ed; exist[ed] = 1;
int prest = ffind(st);
int preed = ffind(ed);
if(prest != preed)
{
pre[prest] = preed;
}
}
}
for(int i = 1 ; i < maxn ; i ++)
{
if(exist[i]) //cout << i << " " << pre[i] << endl;
{
int root = ffind(i);
cnt[root] ++;
//cout << i << " " << root << endl;
}
}
int numtree = 0 , numbird = 0;
for(int i = 1 ; i < maxn ; i ++)
{
if(exist[i] && cnt[i])
{
numtree ++;
numbird += cnt[i];
}
}
cout << numtree << " " << numbird << endl;
int Q ; cin >> Q;
for(int i = 0 ; i < Q ; i ++)
{
int a , b;
cin >> a >> b;
if(ffind(a) != ffind(b))
cout << "No" << endl;
else cout << "Yes" << endl;
}
}