UVa12186:Another Crisis(树形DP)
一道简单的树形DP送给你。
A couple of years ago, a new world wide crisis started, leaving many people with economical problems. Some workers of a particular company are trying to ask for an increase in their salaries.
数年以前,人们遭受了世界范围的经济危机。于是某司工人们要求涨薪。(我百度了一下,金融危机应该降薪才对啊~)
The company has a strict hierarchy, in which each employee has exactly one direct boss, with the exception of the owner of the company that has no boss. Employees that are not bosses of any other employee are called workers. The rest of the employees and the owner are called bosses.
除了公司的拥有者之外,每个雇员都仅有一个上司,(此时一个树形的管理体系呈现在你的眼前),管理链末端的雇员叫做工人,其余的叫老板(领导)。
To ask for a salary increase, a worker should file a petition to his direct boss. Of course, each boss is encouraged to try to make their subordinates happy with their current income, making the company’s profit as high as possible. However, when at least T percent of its direct subordinates have filed a petition, that boss will be pressured and have no choice but to file a petition himself to his own direct boss. Each boss files at most 1 petition to his own direct boss, regardless on how many of his subordinates filed him a petition. A boss only accounts his direct subordinates (the ones that filed him a petition and the ones that didn’t) to calculate the pressure percentage.
工人想涨薪时需要向他的直系领导提交请愿书。当某位管理,他的直系下属至少T%都给他递请愿书的话,他就别无选择只能也向他的上司请愿。而无论他的手下递给他多少份请愿,他只要递给他的上司一份即可。
Note that a boss can have both workers and bosses as direct subordinates at the same time. Such a boss may receive petitions from both kinds of employees, and each direct subordinate, regardless of its kind, will be accounted as 1 when checking the pressure percentage.
注意有些领导可能直系下属中既有管理层又有普通工人,则一视同仁,每个人只计数为1.
When a petition file gets all the way up to the owner of the company, all salaries are increased. The workers’ union is desperately trying to make that happen, so they need to convince many workers to file a petition to their direct boss.
现在工会要动员大家请愿,使得请愿书能一直递到终极boss的手上,他就会给涨薪。
Given the company’s hierarchy and the parameter T, you have to find out the minimum number of workers that have to file a petition in order to make the owner receive a petition.
会给出T的值,你来计算最少要发动多少工人才能达到目的。
Input
There are several test cases. The input for each test case is given in exactly two lines. The first line contains two integers N and T (1 ≤ N ≤ 105 , 1 ≤ T ≤ 100), separated by a single space. N indicates the number of employees of the company (not counting the owner) and T is the parameter described above. Each of the employees is identified by an integer between 1 and N. The owner is identified by the number 0. The second line contains a list of integers separated by single spaces. The integer Bi, at position i on this list (starting from 1), indicates the identification of the direct boss of employee i (0 ≤ Bi ≤ i−1). The last test case is followed by a line containing two zeros separated by a single space.
每组数据给出两行。第一行是N和T,其中N是公司中不包括公司主在内的雇员个数,T是之前题目中的百分之T。公司雇员从1~N编号,接下来的一行按照从第一个到第N个人的顺序给出此人的上司是谁。
Output
For each test case output a single line containing a single integer with the minimum number of workers that need to file a petition in order to get the owner of the company to receive a petition.
每组测试输出一个整数代表最少需要发动的工人数目。
Sample Input
3 100
0 0 0
3 50
0 0 0
14 60
0 0 1 1 2 2 2 5 7 5 7 5 7 5
0 0
Sample Output
3
2
5
提示:前两个样例明确了题目规则,第三个样例通过作图可以想到解题策略。
思路:深搜+排序贪心。对这棵树每一层的子结构都进行贪心选取最小的那几个(具体选几个用T算一下),就可以得到根节点的值。每个工人的值是1,管理层的值是由他对下属(子结构)的选择决定的。
也没什么可说的了,代码中有更具体的注释:
C++11、30ms
1 #include <bits/stdc++.h> 2 #define maxn 100005 3 using namespace std; 4 5 int n, T; 6 vector <int> subordinate[maxn]; 7 8 int dfs(int boss) 9 { 10 int person = subordinate[boss].size(); 11 if (person == 0) return 1;//当这个编号的人是工人时直接返回 12 13 vector <int> temp;//储存各个子结构的值 14 for (int i : subordinate[boss])//遍历当前这个人的下属们 15 temp.push_back(dfs(i)); 16 17 subordinate[boss].clear();//没用了顺手清空 18 19 sort(temp.begin(), temp.end());//排序以便之后贪心选择最少的几个 20 21 int need = (person * T - 1)/100 + 1;//注意这是一个计算最少要选几个人的技巧 22 23 int sum = 0; 24 for (int i = 0; i < need; i++) sum += temp[i]; 25 return sum; 26 } 27 28 int readboss()//数据量达到了十万,普通版的快速读 29 { 30 int x = 0, s = 1, c = getchar(); 31 while (c <= 32) c = getchar(); 32 if (c == '-') s = -1, c = getchar(); 33 for (; isdigit(c); c = getchar()) x = x*10 + c - 48; 34 return x * s; 35 } 36 37 int main() 38 { 39 while (cin >> n >> T && n && T) 40 { 41 for (int i = 1; i <= n; i++)//储存每个人的直系下属 42 subordinate[readboss()].push_back(i); 43 cout << dfs(0) << endl; 44 } 45 }