习题:Maximum Weight Subset(树DP)

题目

传送门

思路

跟距离相关的多半要将距离加入DP状态的定义之中

我们设\(dp[i][j]\)表示以i为根节点的子树距离i最近的选的点的距离大于j的最小权值

我们可以考虑枚举两个儿子来构造距离大于k的情况,

注意距离要从0开始,毕竟要要将i考虑进DP里面

代码

#include<iostream>
#include<vector>
using namespace std;
int n,k;
int val[205];
long long dp[205][205];
/*
以i为根节点的子树,选的深度最小的点的深度大于j的最大权值
*/
vector<int> g[205];
void dfs(int u,int fa)
{
    dp[u][0]=val[u];
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v!=fa)
        {
            dfs(v,u);
            dp[u][0]+=dp[v][k];
        }
    }
    for(int dep=1;dep<=n;dep++)
    {
        for(int i=0;i<g[u].size();i++)
        {
            int son1=g[u][i];
            if(son1!=fa)
            {
                long long now=dp[son1][dep-1];
                for(int j=0;j<g[u].size();j++)
                {
                    int son2=g[u][j];
                    if(son2!=fa&&son2!=son1)
                        now+=dp[son2][max(dep-1,k-dep)];
                }
                dp[u][dep]=max(dp[u][dep],now);
            }
        }
    }   
    for(int i=n-1;i>=0;i--)
        dp[u][i]=max(dp[u][i],dp[u][i+1]);
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        cin>>val[i];
    for(int i=1,u,v;i<n;i++)
    {
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    cout<<dp[1][0];
    return 0;
}
posted @ 2020-07-31 11:52  loney_s  阅读(107)  评论(0)    收藏  举报