描述
小Hi有一棵N个节点的树,编号1-N,其中1号节点是整棵树的根。他把这棵树的N-1条边记录成N-1行,每行2个整数a和b,表示a是b的父节点。
喜欢恶作剧的小Ho在小Hi的记录里加了一行两个整数,于是小Hi不得设法找出这行可疑的记录。具体来说,如果去掉某一行之后,余下N-1行按小Hi的规则(a是b的父节点)恰好能构成一棵N个节点的树,并且满足编号恰好是1-N且1号节点是根,那么被去掉的一行就被视为可疑的。
你能帮小Hi找出所有可疑的记录吗?
输入
第一行包含一个整数N,表示树的节点数目。
以下N行每行两个整数a和b,表示a是b的父节点。
对于30%的数据,1 <= N <= 1000
对于100%的数据, 1 <= N <= 100000, 1 <= a, b <= N
输入保证合法。
输出
输出一行包含若干个从小到大的整数,表示可疑的行号。(行号从1开始)
3 1 2 1 3 1 3
2 3题意:给出n对点,第一个点是第二个的父节点。如果去掉其中一条就可以得到以节点1为根的树。问需要去掉哪条。
思路:样例里面两条边1 3 可以去掉任意一条,所以都写上了。那其实就是多了一条边打破了树的条件:除根节点外有且只有一个父节点。
所以如果是根多了一条边,让根有了父节点,那就把这条去掉。
如果是其它节点多了一条边使得一个节点有多余1个父节点,那就需要找两条任意去掉一条。
#include <bits/stdc++.h>
using namespace std;
const int N = 100021;
int pre[N];
int son[N];
int main()
{
int n;
while (~scanf("%d", &n))
{
int x, y, ans = -1;
memset(pre, 0, sizeof(pre));
for (int i = 0; i < n; i++)
{
scanf("%d%d", &x, &y);
son[i] = y;
if (pre[y] != 0)
{
ans = i;
}else
pre[y] = x;
}
x = y = -1;
if (ans != -1)//说明不是根节点多了父节点
{
for (int i = 0; i < n; i++)
{
if (son[i] == son[ans])
{
if (x == -1)
x = i;
else
y = i;
}
}
printf("%d %d\n", x + 1, y + 1);
}else//根节点多了父节点
{
for (int i = 0; i < n; i++)
if (son[i] == 1)
{
printf("%d\n", i+1);
break;
}
}
}
return 0;
}