Loj10153 二叉苹果树

 

题目描述

有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点。这棵树共 NN 个节点,标号 11 至 NN,树根编号一定为 11。

我们用一根树枝两端连接的节点编号描述一根树枝的位置。一棵有四根树枝的苹果树,因为树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

tree.png

输入格式

第一行两个数 NN 和 QQ ,NN 表示树的节点数,QQ 表示要保留的树枝数量。

接下来 N-1N1 行描述树枝信息,每行三个整数,前两个是它连接的节点的编号,第三个数是这根树枝上苹果数量。

输出格式

输出仅一行,表示最多能留住的苹果的数量。

 

一眼,是树形DP,其中dp[i][j]代表以i为根节点的子树中,保留j个节点能取到的最大数量。

对于每一个节点,枚举左子树的保留节点数,则右子树保留节点数就是总结点数减去左子树。

根据这个进行记忆化搜索。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#define in(a) a=read()
#define REP(i,k,n)  for(int i=k;i<=n;i++)
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            f=-1;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return x*f;
}
int n,m;
int l[1010],r[1010],s[1010];
int f[110][110];
inline int dfs(int i,int j){
    if(!j)  return 0;
    if(!l[i] && !r[i])  return s[i];
    if(f[i][j])  return f[i][j];
    REP(k,0,j-1)
        f[i][j]=max(f[i][j],dfs(l[i],k)+dfs(r[i],j-k-1)+s[i]);
    return f[i][j];
}
int total,head[1010],to[1010],nxt[1010],val[1010];
inline void adl(int a,int b,int c){
    total++;
    to[total]=b;
    val[total]=c;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void get(int u,int fa){
    for(int e=head[u];e;e=nxt[e])
        if(to[e]!=fa){
            if(!l[u])  l[u]=to[e];
            else  r[u]=to[e];
            s[to[e]]=val[e];
            get(to[e],u);
        }
    return ;
}
int main(){
    in(n),in(m);
    int a,b,c;
    REP(i,1,n-1)  in(a),in(b),in(c),adl(a,b,c),adl(b,a,c);
    get(1,0);
    cout<<dfs(1,m+1)<<endl;
    return 0;
}

 

posted @ 2018-12-01 10:15  Dijkstra·Liu  阅读(256)  评论(0编辑  收藏  举报