贪心算法New Year BonusGrant

来源:互联网 发布:老外中国快递知乎 编辑:程序博客网 时间:2024/05/22 06:30

 

New Year BonusGrant

 

All programmers of Mocrosoft softwarecompany are organized in a strict subordination hierarchy. Every programmer hasexactly one chief, except Bill Hates who is also the head of the company andhas no chief.

Due to the celebration of the new 2003year, chief accountant of Mocrosoft decided to pay a New Year Bonus Grant of1000 dollars to some programmers. However being extremely concerned of the companywealth she would like to designate the least possible amount of money for thesegrants. On the other hand she didn��t want to be accused of being too greedy or of givingpreferences to some programmers. To do this, she developed the following schemeof 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 himselfwould not receive money. But programmers somehow discovered the plan of chiefaccountant and decided to make a trick to get the most money possible and sharethem fairly afterwards. The idea was to make such grant assignments that thetotal amount of grant money received is maximum possible.

You were selected to write the programwhich will find the optimal grants appointment.



This problem containsmultiple test cases!

The first line of a multiple input is aninteger N, then a blank line followed by N input blocks. Each input block is inthe format indicated in the problem description. There is a blank line betweeninput blocks.

The output format consists of N outputblocks. There is a blank line between output blocks.



Input

The first line of the input file containsinteger N - the number of programmers in Mocrosoft company (2 <= N <= 500000). Each programmer is assigned his unique identifier - integer numberranging from 1 to N. Bill Hates has number 1 and each programmer has the numbergreater then the number of his chief. The second line of the input file containsN - 1 integers, i-th of which being the number of the chief of the worker whosenumber is (i + 1).



Output

On the first line of the output file printthe maximum possible amount of money workers can get. On the second line outputthe numbers of programmers that will receive grant in ascending order.



Sample Input

1

4
1 1 2



Sample Output

2000
3 4

题目意思:Mocrosoft公司有着严格的等级制度,每个人有且仅有一位直接顶头上司除了Bill Hates——他是公司的老总,没有上司。现在想给一些员工每人1000的奖金,但是选人得满足一下三条规则:

1、             一个人可以从他直接上司那被选中或者选中他的一位直接下级或者什么都不做

2、             没有一个人可以同时被他上司选中并且选中他的一位直接下级

3、             一个人最多选中他的一位直接下属

Bill Hates不参加奖金评选。现在需要找到最优的方案并输出。

 

解题思路:

本题和图的着色问题很像。解决这类问题的一个通用突破点是拓扑排序+贪心算法。由于本题的输入就是一个拓扑排序,因此本题仅仅只需运用贪心算法即可。为了方便计算,我们把每个结点的颜色分位三类:0——初始状态,1——该结点被选中,2——该节点有子结点被选中。如果某个结点的结点颜色状态为2的话就说明该结点的其他子结点不能被选中。具体的思路如下:我们首先从最下一层的叶子节点开始查找(即程序中对应的从最后一个结点开始查找),如果该结点没有被选中并且该结点的子结点没有一个被选中的则选择该节点。为了方便写程序,我们这么处理:如果一个结点的颜色状态不为2并且该结点的父母结点的颜色状态也不为2,则将此结点的颜色状态置为1并且将该结点父母结点的颜色状态置为2即可。这种方法的正确性体现在输入按照题目的要求输入后,从n到1是一个逆拓扑排序。

贪心算法体现在:如果从非叶子节点开始选择,则至多在其本身、其叶子节点、兄弟结点中选择一个,而从其叶子节点开始选择,则在在其本身、其叶子节点、兄弟结点中至少可以选择一个。从而体现了贪心。

具体程序如下:

 

#include<stdio.h>       //gets函数所在的头文件

#include<iostream>

using namespacestd;

 

#define maxn500005       //最大员工数目

 

struct Node

{

       int parents;//记录i的父母结点

       int color;//结点颜色标识:0-初始化,1-选择该结点,2-改结点已有一个子结点被选中

};

Node nodes[maxn];

void result(intn);//用来求最终的结果

int main()

{

       int N;

       cin>>N;

       while(N>0)

       {

              char void_line[10];

              gets(void_line);//注意每次输入时这里应该读取一行空行

              int n;

              cin>>n;

              if(n==1)

                     cout<<0<<endl;

              else

                     result(n);

              N-=1;

       }

       return 0;

}

 

void result(int n)

{

       nodes[1].parents=0;

       nodes[1].color=0;

       int parent;

       int counts=0;

       for(int i=2;i<=n;i++)

       {

              //录入输入信息

              cin>>parent;

              nodes[i].parents=parent;

              nodes[i].color=0;

       }

       //n1是一个逆拓扑排序,任何一个都行

       for(inti=n;i>1;i--)

       {

              //该结点的父母结点还没有选中任何一个子结点和该节点没有选中任何一个子结点

              if((nodes[nodes[i].parents].color!=2)&&(nodes[i].color!=2))

              {

                     nodes[i].color=1;//选中

                     nodes[nodes[i].parents].color=2;

                     counts+=1;

              }

       }

       cout<<1000*counts<<endl;

       for(int i=2;i<=n;i++)

       {

              if(nodes[i].color==1)

              {

                     if(i!=n)

                            cout<<i<<"";

                     else

                            cout<<i;

              }

       }

       cout<<endl;

}

0 0
原创粉丝点击