题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1315
题目意思:Bill Hates 是公司的老总,她管辖着很多程序员,每个程序员都有各自的上头。现在为了庆祝2013年的到来,要向这些程序员发放新年奖金。不过要遵循一些规则:
1、每个程序员要不把奖金给予她的其中一个下属,要把就等着她的上司发奖金给她。
2、每个程序员不能同时接收奖金和分发奖金。
3、如果程序员要把奖金给予她的下属,她的下属只能是一个,不能是多个。
首先说明一下Simple Input 代表什么意思。
1 ——> test case
4 ——> 包括Bill Hates 在内的公司总人数
1 1 2 ——> 编号为2的人的上司是1(Bill Hates),编号为3的人的上司也是1,编号为4的人上司是2
可以得到这样一幅图。
其实可以将问题抽象成一棵树。
那么题目就变成要我们求出这样的一些点:
(1)儿子和父亲不能同时染色
(2)兄弟中只能有一个点被染色
可以从树的底部开始往上找,如果某个节点被染色,那么它的父亲就不能被染色,所以要用到一个标记数组vis[]。可以发现,实现过程中其实不需要检查兄弟节点是否被染色的。还有一点就是special judge,答案是不唯一的。例如对于5 1 1 2 4 答案可以为 3 5,或者是2 5。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 500000 + 5; 7 int fa[maxn]; 8 int vis[maxn], ans[maxn]; 9 10 int main() 11 { 12 int T, n; 13 while (scanf("%d", &T) != EOF) 14 { 15 while (T--) 16 { 17 scanf("%d", &n); 18 for (int i = 2; i <= n; i++) 19 scanf("%d", &fa[i]); // 编号为 i 的点的父亲 20 memset(vis, 0, sizeof(vis)); 21 int cnt = 0; 22 for (int i = n; i >= 2; i--) 23 { 24 if (!vis[i] && !vis[fa[i]]) 25 { 26 vis[i] = vis[fa[i]] = 1; 27 ans[cnt++] = i; 28 } 29 } 30 printf("%d\n", cnt * 1000); 31 for (int i = cnt-1; i >= 0; i--) 32 { 33 if (i == cnt-1) 34 printf("%d", ans[i]); 35 else 36 printf(" %d", ans[i]); 37 } 38 puts(""); 39 } 40 } 41 return 0; 42 }