CodeForces 1249 F Maximum Weight Subset(树形dp))

题目:

      F.Maximum Weight Subset

思路:

      显然是树形dp没错了,重点在于如何处理和如何转移.
我的做法是:
    dp[i][j] 表示距结点 i 最近为 j 的点集的最大权重和.
    每次由叶子结点往父亲节点转移,很明显对于父亲结点 u, 叶子结点 v, dp[u][j] 最多只能有 一个 叶子结点可以 为 j,其他的节点必须是max(k-j,j),否则会导致选择的点集里面有距离大于 k 的点对.
    同时dp[u][j] 还可以向 dp[u][j-1]转移,取最大值.

Ac_Code:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define fir first
#define sec second
using namespace std;
 
const int maxn = 300;
const long long INF = 1e16;
 
 
int n,k,e;
int a[maxn];
int head[maxn],edge[maxn<<1],nex[maxn<<1];
long long dp[maxn][maxn];
long long Cg[maxn][maxn];
long long ans = 0;
void add(int l,int r) {
    edge[++e] = r;
    nex[e] = head[l];
    head[l] = e;
}
 
void dfs(int u,int f) {
    dp[u][0] = a[u];
    for(int i=head[u];i;i=nex[i]) {
        int v = edge[i];
        if(v==f) continue;
        dfs(v,u);
        for(int i=0;i<=k;i++) {
            long long val = dp[v][max(k-i-1,i-1)];
            dp[u][i] += val;
            Cg[u][i] = max(Cg[u][i],dp[v][i-1] - val);
        }
    }
    for(int i=k;i>=0;i--) {
        if(Cg[u][i] >= 0) dp[u][i] += Cg[u][i];
        dp[u][i] = max(dp[u][i+1],dp[u][i]);
        ans = max(ans,dp[u][i]);
        //printf("dp[%d][%d] = %lld\n", u,i,dp[u][i]);
    }
}
 
int main() {
    scanf("%d%d",&n,&k);
    k++;
    for(int i=0;i<=n;i++) for(int j=0;j<=k;j++) Cg[i][j] = -INF;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=0;i<n-1;i++) {
        int l,r;
        scanf("%d%d",&l,&r);
        add(l,r);
        add(r,l);
    }
    dfs(1,0);
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(CF200题计划,DP)