ACdream oj 1212 New Year Bonus Grant(贪心+拓扑排序)

题目链接

New Year Bonus Grant

Special Judge Time Limit: 6000/3000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Problem Description
      All programmers of Mocrosoft software company are organized in a strict subordination hierarchy. Every programmer has exactly one chief, except Bill Hates who is also the head of the company and has no chief.
      Due to the celebration of the new 2003 year, chief accountant of Mocrosoft decided to pay a New Year Bonus Grant of 1000 dollars to some programmers. However being extremely concerned of the company wealth she would like to designate the least possible amount of money for these grants. On the other hand she didn’t want to be accused of being too greedy or of giving preferences to some programmers. To do this, she developed the following scheme of grants appointment:
• Each programmer may either assign a grant to one of his subordinates or have a grant assigned to him by his chief or none of the above.
• No programmer can simultaneously receive a grant and assign a grant to one of his subordinates.
• No programmer can assign a grant to more than one of his subordinates
      The scheme seemed to be designed perfectly — nobody would like to assign a grant to anybody since in this case he himself would not receive money. But programmers somehow discovered the plan of chief accountant and decided to make a trick to get the most money possible and share them fairly afterwards. The idea was to make such grant assignments that the total amount of grant money received is maximum possible.
      You were selected to write the program which will find the optimal grants appointment.
Input
      The first line of the input file contains integer N — the number of programmers in Mocrosoft company (2 ≤ N ≤ 500 000). Each programmer is assigned his unique identifier — integer number ranging from 1 to N . Bill Hates has number 1 and each programmer has the number greater then the number of his chief. The second line of the input file contains N − 1 integers, i-th of which being the number of the chief of the worker whose number is (i + 1).
Output
      On the first line of the output file print the maximum possible amount of money workers can get. On the second line output the numbers of programmers that will receive grant in ascending order.
Sample Input
4
1 1 2
Sample Output
2000
3 4
Source
Andrew Stankevich Contest 1

题意:一颗树,根节点不可选。要满足以下条件:

1,父亲和儿子不能同时选

2,兄弟之间不能同时选

问最多能选多少个,输出方案?


题解:贪心:从叶子开始选,选了以后把该点和跟该点关联的点删除,一直重复直至不能再选。具体可以用拓扑排序来实现。因为这题儿子的编号一定比父亲高,所以直接从最大的数开始选就行了。

简要证明:对于某个叶子节点,假设一个点集,包含该叶子节点和它的父亲,以及兄弟。这个点集有且仅能选一个。假设我们选了叶子节点,那么对于该点集外的点来说,是不会受到影响的。假设选了父亲节点,那么父亲节点会影响它的父亲以及兄弟,也就是说影响了该点集外的点。假设选了兄弟节点非叶子节点,那么会影响该节点的儿子节点,也影响了点集外的点。所以选叶子节点一定是最优的。

代码如下:

#include<stdio.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#define inff 0x3fffffff
#define eps 1e-8
#define nn 510000
#define mod 1000000007
typedef long long LL;
const LL inf64=LL(inff)*inff;
using namespace std;
int n;
int fa[nn];
bool use[nn];
int ve[nn];
int main()
{
    int i;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=2;i<=n;i++)
        {
            scanf("%d",&fa[i]);
        }
        for(i=1;i<=n;i++)
            use[i]=false;
        int ans=0;
        int lv=0;
        for(i=n;i>1;i--)
        {
            if(!use[i])
            {
                if(!use[fa[i]])
                {
                    ve[lv++]=i;
                    ans++;
                }
                use[i]=true;
                use[fa[i]]=true;
            }
        }
        printf("%d\n",ans*1000);
        for(i=lv-1;i>=0;i--)
        {
            printf("%d%c",ve[i],i==0?'\n':' ');
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值