P2015二叉苹果树 (树上DP)

P2015 二叉苹果树
提交
15.30k
通过
7.27k
时间限制
1.00s
内存限制
125.00MB
提交答案
加入收藏
题目提供者
洛谷
难度
普及/提高-
历史分数
100
提交记录 查看题解
标签
进入讨论版
相关讨论
推荐题目
展开
题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)

这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。

我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树

2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。

给定需要保留的树枝数量,求出最多能留住多少苹果。

输入格式
第1行2个数,N和Q(1<=Q<= N,1<N<=100)。

N表示树的结点数,Q表示要保留的树枝数量。接下来N-1行描述树枝的信息。

每行3个整数,前两个是它连接的结点的编号。第3个数是这根树枝上苹果的数量。

每根树枝上的苹果不超过30000个。

输出格式
一个数,最多能留住的苹果的数量。

输入输出样例
输入 #1复制
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出 #1复制
21

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <queue>
#include <climits>
#include <stack>
#include <map>
#include <cmath>
#include <set>
#include <cstdlib>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
template<typename T>void write(T x)
{
    if (x<0)
    {
        putchar('-');
        x=-x;
    }
    if (x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while (!isdigit(ch)) {        
if (ch == '-')f*=-1;ch=getchar();    
}
    while (isdigit(ch)){        
x = x*10+ch-48;ch=getchar();    
}x*=f;
}
const int maxn=150;
int head[maxn],dp[maxn][maxn];
 int n,m,a,b,c;
struct node{
  int to,next,w;
}e[maxn*2];
int tot,sz[maxn];
void add(int u,int v,int w){
    e[++tot].to=v;
    e[tot].w=w;
    e[tot].next=head[u];
    head[u]=tot;
}
void dfs(int u,int fa){
   for(int i=head[u];i;i=e[i].next){
       int v=e[i].to;
       if(v==fa)continue;
       dfs(v,u);
       sz[u]+=sz[v]+1;
    for(int j=min(sz[u],m);j>0;j--){
        for(int k=min(sz[v],j-1);k>=0;k--){
            dp[u][j]=max(dp[u][j],dp[u][j-k-1]+dp[v][k]+e[i].w);
        }
    }
   }
}
int main() {
 
  read(n);
  read(m);
  rep(i,1,n-1){
      read(a);
      read(b);
      read(c);
      add(a,b,c);
      add(b,a,c);
  }
  dfs(1,0);
  write(dp[1][m]);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值