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 k−j 。
最后对 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;
}

浙公网安备 33010602011771号