Step1 Problem:
给你很多棵树,一共有N个节点, 树上节点有若干个宝物,你想获取该节点宝物,你就必须先获取该节点父亲的宝物。你只能获取M个节点的宝物,求获取宝物最大数量。
Step2 Involving algorithms:
树形DP && 01背包
Step3 Ideas:
用0节点 将很多棵树 连接成一棵树。
状态dp[u][j]:代表 u 这棵子树 拿 j 个节点的宝物最大数量
状态转移方程:dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[to][k]);// j 是 u 的容量,to 是子树,k是从子树 to 选择节点数量
用每棵子树 更新 当前树(能获取节点数量 就是容量) 能获取宝物最大数量
01背包
for:u 节点的子树
for:当前树的容量
更新宝物最大数量
Step4 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 500;
struct node
{
int to, next;
};
node Map[N];
int head[N], cnt;
int dp[N][N], a[N];
void dfs(int u, int f, int m)
{
dp[u][1] = a[u];
if(m == 1) return ;//能获取节点数量是1的时候,最大就是自身。
for(int i = head[u]; ~i; i = Map[i].next)//u 的每一棵子树
{
int to = Map[i].to;
if(to != f)
{
dfs(to, u, m - 1);
for(int j = m; j >= 2; j--)//到达 u 点后 的容量
{
for(int k = 1; k <= j-1; k++)//该子树上选择k个节点 j-1 to 1 也是可以的
{
dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[to][k]);
}
}
}
}
}
void add(int u, int v)
{
Map[cnt] = (node){v, head[u]};
head[u] = cnt++;
}
int main()
{
int n, m, u;
while(~scanf("%d %d", &n, &m) && (n||m))
{
memset(head, -1, sizeof(head));
cnt = 0;
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &u, &a[i]);
add(u, i);
}
dfs(0, -1, m+1);//从0开始,所以获取节点数量+1
printf("%d\n", dp[0][m+1]);
}
return 0;
}