luoguP2015 二叉苹果树 树形dp

题面

这题有树 有 d p dp dp 所以就是树 d p dp dp

d p [ i ] [ j ] dp[i][j] dp[i][j]表示在节点 i i i下面取 j j j个节点可以获得的苹果最大值
l s [ i ] ls[i] ls[i]表示 i i i的左儿子节点 , , r s [ i ] rs[i] rs[i]表示 i i i的右儿子节点
这两个在 d f s dfs dfs建树的过程中就可以维护
我们用记忆化搜索来实现 d p dp dp
s f d ( i , j ) sfd(i,j) sfd(i,j)的返回值表示在节点 i i i下面取 j j j个节点可以获得的苹果最大值
所以转移方程如下:
k j = { d p [ i ] [ j ] = m a x { d p [ i ] [ j ] , s f d ( r s [ i ] , j − 1 ) + r v [ i ] } , k = 0 d p [ i ] [ j ] = m a x { d p [ i ] [ j ] , s f d ( l s [ i ] , j − 1 ) + l v [ i ] } , k = j d p [ i ] [ j ] = m a x { d p [ i ] [ j ] , s f d ( l s [ i ] , k − 1 ) + s f d ( r s [ i ] , j − k − 1 ) + l v [ i ] + r v [ i ] } ; , 0 < k < j k_j=\begin{cases} dp[i][j]=max\{dp[i][j],sfd(rs[i],j-1)+rv[i]\} ,k=0\\ dp[i][j]=max\{dp[i][j],sfd(ls[i],j-1)+lv[i]\} ,k=j\\ dp[i][j]=max\{dp[i][j],sfd(ls[i],k-1)+sfd(rs[i],j-k-1)+lv[i]+rv[i]\}; ,0<k<j\\ \end{cases} kj=dp[i][j]=max{dp[i][j],sfd(rs[i],j1)+rv[i]}k=0dp[i][j]=max{dp[i][j],sfd(ls[i],j1)+lv[i]}k=jdp[i][j]=max{dp[i][j],sfd(ls[i],k1)+sfd(rs[i],jk1)+lv[i]+rv[i]};0<k<j

#include<bits/stdc++.h>
using namespace std;
inline void read(int &x){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
    x=s*w;
}
struct node
{
    int to,val,nxt;
}edge[300];
int n,m,x,y,z,cnt,head[110],ls[110],rs[110],lv[110],rv[110],dp[110][110];
inline void addedge(int u, int v, int w){
    edge[++cnt].to=v,edge[cnt].val=w;
    edge[cnt].nxt=head[u],head[u]=cnt;
}
inline void superadd(int u, int v, int w){
    addedge(u,v,w),addedge(v,u,w);
}
void dfs(int u, int fa){
    for(int i=head[u];i;i=edge[i].nxt){
        int vv=edge[i].to;
        if(vv==fa)continue;
        if(!ls[u])ls[u]=vv,lv[u]=edge[i].val;
        else rs[u]=vv,rv[u]=edge[i].val;
        dfs(vv,u);
    }
}
int sfd(int i, int j){
    if(!ls[i]&&!rs[i])return 0;
    if(dp[i][j])return dp[i][j];
    if(j==0)return 0;
    for(int k=0;k<=j;k++){
        if(k==0)dp[i][j]=max(dp[i][j],sfd(rs[i],j-1)+rv[i]);
        else if(k==j)dp[i][j]=max(dp[i][j],sfd(ls[i],j-1)+lv[i]);
        else dp[i][j]=max(dp[i][j],sfd(ls[i],k-1)+sfd(rs[i],j-k-1)+lv[i]+rv[i]);
    }
    return dp[i][j];
}
int main(){
    read(n),read(m);
    for(int i=1;i<n;i++)read(x),read(y),read(z),superadd(x,y,z);
    dfs(1,0);
    printf("%d\n",sfd(1,m));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值