Codeforces Round #595 (Div. 3) F. Maximum Weight Subset(树形dp)

传送门

题意:

给出一棵树,有 n n n个节点,每个节点都有一个点权,选出点权和最大的点集,满足每个点之间的距离都大于 k k k

题解:

容易想到树形 d p dp dp

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以 i i i为根的子树,选出的点中与 i i i​ 最近的距离为 j j j

1. 1. 1. 如果节点 i i i 要选,那么 d p [ i ] [ 0 ] = a [ i ] + ∑ d p [ s o n ] [ k ] dp[i][0]=a[i]+\sum dp[son][k] dp[i][0]=a[i]+dp[son][k]

2. 2. 2. 如果节点 i i i 不选,那么先枚举 j j j ,再枚举距离为 j j j 的点在哪棵子树内,那么对于其他子树,距离就必须要是 k − j k-j kj

最后对 d p dp dp数组维护后缀最大值即可。

具体看代码:

#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e2+5;
const int inf=0x3f3f3f3f;
int dp[MAXN][MAXN];
vector<int> g[MAXN];
int a[MAXN];
int n,k;
void dfs(int u,int f)
{
    dp[u][0] = a[u];
    for(auto v:g[u])
    {
        if(v==f)
            continue;
        dfs(v, u);
        dp[u][0] += dp[v][k];
    }
    for (int dep = 1; dep < n;dep++)
    {
        for(auto v:g[u])
        {
            if(v==f)
                continue;
            int sum = dp[v][dep - 1];
            for(auto t:g[u])
            {
                if(t==f||t==v)
                    continue;
                sum = sum + dp[t][max(dep - 1, k - dep)];
            }
            dp[u][dep] = max(dp[u][dep], sum);
        }
    }
    for (int dep = n - 1; dep >= 0;dep--)
    {
        dp[u][dep] = max(dp[u][dep], dp[u][dep + 1]);
    }
}
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n;i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= n - 1;i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    int ans = dp[1][0];
    cout << ans << endl;
}
posted @ 2021-08-11 14:23  TheBestQAQ  阅读(40)  评论(0)    收藏  举报