HDU 4169 Wealthy Family(树形DP)

Problem Description
While studying the history of royal families, you want to know how wealthy each family is. While you have various 'net worth' figures for each individual throughout history, this is complicated by double counting caused by inheritance. One way to estimate the wealth of a family is to sum up the net worth of a set of k people such that no one in the set is an ancestor of another in the set. The wealth of the family is the maximum sum achievable over all such sets of k people. Since historical records contain only the net worth of male family members, the family tree is a simple tree in which every male has exactly one father and a non-negative number of sons. You may assume that there is one person who is an ancestor of all other family members.
 
Input
The input consists of a number of cases. Each case starts with a line containing two integers separated by a space: N (1 <= N <= 150,000), the number of people in the family, and k (1 <= k <= 300), the size of the set. The next N lines contain two non-negative integers separated by a space: the parent number and the net worth of person i (1 <= i <= N). Each person is identified by a number between 1 and N, inclusive. There is exactly one person who has no parent in the historical records, and this will be indicated with a parent number of 0. The net worths are given in millions and each family member has a net worth of at least 1 million and at most 1 billion.
 
Output
For each case, print the maximum sum (in millions) achievable over all sets of k people satisfying the constraints given above. If it is impossible to choose a set of k people without violating the constraints, print 'impossible' instead.
 
题目大意:给n个点,每个点有一个权值,要求选k个点,这k个点任意一个点不能为其他点的父节点,求最大总权值。
思路:树形DP。ex[i]代表从开始遍历到某点x及其子节点(包括x)选i个点可以得到的最大总权值,now[i]代表从开始遍历到某点x及其子节点(不包括x)选i个点可以得到的最大总权值,函数一开始的时候ex是代表遍历到x之前的选i个点可以得到的最大总权值,那么在dfs算出now之后,ex[i] = max(now[i], ex[i-1] + a)就可以保证没有选的两个点是不符合要求的。
 
 1 #include <cstdio>
 2 #include <cstring>
 3 
 4 const int MAXN = 150010;
 5 
 6 int head[MAXN], next[MAXN], to[MAXN];
 7 int a[MAXN];
 8 int ecnt, n, k;
 9 int ans[310];
10 
11 inline void addEdge(int u, int v) {
12     to[ecnt] = v;
13     next[ecnt] = head[u]; head[u] = ecnt++;
14     //printf("%d->%d\n",u,v);
15 }
16 
17 inline void init() {
18     memset(head, 0, sizeof(head));
19     memset(ans, 255, sizeof(ans));
20     ecnt = 2;
21     int f;
22     for(int i = 1; i <= n; ++i) {
23         scanf("%d%d", &f, &a[i]);
24         addEdge(f, i);
25     }
26 }
27 
28 inline void _max(int &a, const int &b) {
29     if(a < b) a = b;
30 }
31 
32 void dfs(int u, int *ex) {
33     int *now = new int[310];
34     for(int i = 0; i <= k; ++i) now[i] = ex[i];
35     for(int p = head[u]; p; p = next[p]) {
36         dfs(to[p], now);
37     }
38     ex[0] = 0;
39     for(int i = k; i > 0; --i) {
40         ex[i] = now[i];
41         if(ex[i-1] != -1) {
42             _max(ex[i], ex[i-1] + a[u]);
43         }
44     }
45     delete [] now;
46 }
47 
48 int main() {
49     while(scanf("%d%d", &n, &k) != EOF) {
50         init();
51         dfs(0,ans);
52         if(ans[k] == -1) puts("impossible");
53         else printf("%d\n", ans[k]);
54     }
55     return 0;
56 }
View Code

 

转载于:https://www.cnblogs.com/oyking/p/3199686.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值