Problem Description
ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?
Input
每个测试实例首先包括2个整数,N,M.(1 <= M <= N <= 200);在接下来的N行里,每行包括2个整数,a,b. 在第 i 行,a 代表要攻克第 i 个城堡必须先攻克第 a 个城堡,如果 a = 0 则代表可以直接攻克第 i 个城堡。b 代表第 i 个城堡的宝物数量, b >= 0。当N = 0, M = 0输入结束。
Output
对于每个测试实例,输出一个整数,代表ACboy攻克M个城堡所获得的最多宝物的数量。
Sample Input
3 2
0 1
0 2
0 3
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
0 0
Sample Output
5
13
思路:树形DP, dp[i][j]表示当节点为i时攻克j个点时获得的财富, 根节点为0开始。要注意的是根节点不用攻克自己完全选择它的子树就可, 而非根节点至少要攻克它自己本身,然后在从子树中选择攻克的数量,
code:
#include <cstdio>
#include <cstring>
#define max(a, b) (a)>(b)? (a):(b)
using namespace std;
struct node
{
int v, next;
}edge[202];
int cnt = 0, n = 0, m = 0, value[202], head[202], uead[202], dp[202][202];
void addedge(int u, int v)
{
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void dfs(int cur)
{
int i = 0, j = 0, t = 0, p = 0, v = 0, max = 0;
dp[cur][0] = 0;
for(p = head[cur]; p != -1; p = edge[p].next)
{
v = edge[p].v;
dfs(v);
for(i = m; i>0; i--)
{
max = dp[cur][i];
if(cur == 0) t = i;//由于点0不用攻克, 所以当节点为0时只选它的子树
else t = i-1;//不是根节点, 要攻克它自身
for(j = 0; j<=t; j++)
max = max(max, dp[v][j]+dp[cur][i-j]);
// if(cur == 0) j = 0; //与上面转移方程一样
// else j = 1;
// for(; j<=i; j++)
// max = max(max, dp[v][i-j]+dp[cur][j]);
dp[cur][i] = max;
}
}
for(i = 1; i<=m; i++)//加上自己本身
dp[cur][i] += value[cur];
}
int main()
{
int i = 0, u = 0, ans = 0, cost = 0, n = 0, cnt2 = 0, num[202];
while(scanf("%d %d", &n, &m), n+m)
{
value[0] = 0;
memset(head, -1, sizeof(head));
memset(edge, 0, sizeof(edge));
memset(dp, 0, sizeof(dp));
cnt = cnt2 = 0;
for(i = 0; i<n; i++)
{
scanf("%d %d", &u, &cost);
value[i+1] = cost;
addedge(u, i+1);
}
dfs(0);
printf("%d\n", dp[0][m]);
}
return 0;
}