【树形DP && 01背包】HDU - 1561 The more, The Better

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个节点
                {
                    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;
}

猜你喜欢

转载自blog.csdn.net/bbbbswbq/article/details/80075336
今日推荐