农夫约翰有 N 头奶牛,编号 1∼N。
通过使用易拉罐和绳子构成的土制电话,它们会在约翰不注意的时候相互通信。
每头奶牛最多可以将消息转发给另一头奶牛:
对于奶牛 i,它会将自己收到的任何信息转发给奶牛 Fi(Fi 与 i 一定不同)。
如果 Fi 为 0,则奶牛 i 不转发消息。
不幸的是,奶牛们意识到来自某些奶牛的消息可能最终陷入循环之中,不断地被转发。
请确定所有奶牛中有多少只奶牛发出的消息不会永远陷入循环之中。
输入格式
第一行包含整数 N。
接下来 N 行,每行包含一个整数 Fi。
输出格式
输出发出的消息不会陷入循环的奶牛的数量。
数据范围
1≤N≤1000,
0≤Fi≤N
输入样例:
5
0
4
1
5
4
输出样例:
2
样例解释
奶牛 1 不发送任何信息,因此不会陷入循环。
奶牛 3 发送信息给奶牛 1,因此也不会陷入循环。
其他三头奶牛发送的信息都会陷入循环。
代码:
// 查找图中有多少普通树 (要么是普通树要么是基环树(点数等于边数))
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int f[N];
int p[N];
int cnt[N];
int n;
int find(int x)
{
if (f[x] != x)
f[x] = find(f[x]);
return f[x];
}
void merge(int a, int b)
{
int t1 = find(a);
int t2 = find(b);
if (t1 != t2)
{
f[t1] = t2;
cnt[t2] += cnt[t1];
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
f[i] = i;
cnt[i] = 1;
}
// 若有环 则并查集根节点为环上某个点(最后放入的那条边上的点 并不会无限递归) 若根节点还有父节点则为基环树
for (int i = 1; i <= n; i++)
{
cin >> p[i];
if (p[i])
merge(i, p[i]);
}
int res = 0;
for (int i = 1; i <= n; i++)
{
if (f[i] == i && !p[i])
res += cnt[i];
}
cout << res << endl;
return 0;
}