vijos 1676 淘淘吃苹果

陶陶吃苹果

背景

陶陶很喜欢吃苹果。

描述

curimit知道陶陶很喜欢吃苹果。于是curimit准备在陶陶生日的时候送给他一棵苹果树。

curimit准备了一棵这样的苹果树作为生日礼物:这棵苹果树有n个节点,每个节点上有c[i]个苹果,这棵树高度为h。

可是,当curimit把这棵树给陶陶看的时候,陶陶却说:“今年生日不收礼,收礼只收节点数减高度不超过k的苹果树。”这下curimit犯难了,curimit送来的树枝繁叶茂,不满足节点数-高度≤k。于是curimit决定剪掉一些枝条,使得修剪过后的树满足节点数-高度≤k,但是curimit又想保留尽量多的苹果数目。curimit想请你帮他算算经过修剪后的树最多能保留多少个苹果。

注:
一, 节点1为树根,不能把它剪掉。

二, 1个节点的树高度为1。

格式

输入格式

输入文件的第一行为两个整数n,k分别表示这棵树有n个节点,修剪后的树节点数-高度≤k。

第二行开始到第n+1行,每行有两个数,第i+1行的两个数father[i]和c[i]分别表示节点i的父亲是father[i]和节点i处有c[i]个苹果。

规定:节点1的父亲为0。

输出格式

输出文件仅包含一行,ans,表示在满足修建后的树节点数-高度≤k的条件下,最多能保留多少个苹果。

样例1

样例输入1

5 1
0 1
1 1
1 3
2 10
3 4

Copy

样例输出1

15

Copy

限制

全部1秒

提示

【约定】
对于10%的数据, n≤10
对于30%的数据, n≤100 0≤k≤20
对于100%的数据,n≤4000 0≤k≤=500

来源

思路: 树形dp 

点点点

代码: 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N =4005;
ll dp1[N][505];
ll dp2[N][505];
ll sum[N];
ll c[N];
int rt;
vector< int >ve[N];

int n,k,m;

void dfs1(int u)
{
    for(int i=0;i<ve[u].size();i++){
        int v=ve[u][i];
        sum[v]=sum[u]+c[v];
        for(int j=0;j<=m;j++) dp1[v][j]=dp1[u][j];
        dfs1(v);
        for(int j=1;j<=m;j++) dp1[u][j]=max(dp1[u][j],dp1[v][j-1]+c[v]);  //依赖性体现在这个方程中
    }
}

void dfs2(int u)
{
    for(int i=ve[u].size()-1;i>=0;i--){
        int v=ve[u][i];
        sum[v]=sum[u]+c[v];
        for(int j=0;j<=m;j++) dp2[v][j]=dp2[u][j];
        dfs2(v);
        for(int j=1;j<=m;j++) dp2[u][j]=max(dp2[u][j],dp2[v][j-1]+c[v]);
    }
}

int main()
{
    int u;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d %lld",&u,&c[i]);
        if(!u){
            rt=i;
        }
        else{
            ve[u].push_back(i);
        }
    }

    sum[rt]=c[rt];
    dfs1(rt);
    dfs2(rt);
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(ve[i].size()==0){
            for(int j=0;j<=m;j++){
                ans=max(ans,dp1[i][j]+dp2[i][m-j]+sum[i]);
            }
        }
    }
    cout<<ans<<endl;

    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值