P2015 二叉苹果树

苹果二叉树

有一棵二叉苹果树,如果树枝有分叉,一定是分两叉,即没有只有一个儿子的节点。

这棵树共 \(N\) 个节点,编号为 \(1\)\(N\),树根编号一定为 \(1\)

我们用一根树枝两端连接的节点编号描述一根树枝的位置。

一棵苹果树的树枝太多了,需要剪枝。但是一些树枝上长有苹果,给定需要保留的树枝数量,求最多能留住多少苹果。

这里的保留是指最终与1号点连通。

输入格式

第一行包含两个整数 \(N\)\(Q\),分别表示树的节点数以及要保留的树枝数量。

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

输出格式

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

数据范围

\(1≤Q<N≤100\)
\(N≠1\)
每根树枝上苹果不超过 \(30000\) 个。

输入样例:

5 2
1 3 1
1 4 10
2 3 20
3 5 20

输出样例:

21

题解

树形动态规划没得跑,

\(f[u][j]\)表示\(u\)这个节点选择\(j\)条边的最大价值

每一棵子树看出一组背包,若需要选择子树\(son\)的时候,则根结点u到子树\(son\)的边一定用上,因此能用上的总边数一定减\(1\),总共可以选择\(j\)条边时,当前子树\(son\)分配的最大边数是\(k\),那么\(u\)为根的子树的分配数量是\(j-k-1\)

\(f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+e[i])\)

#include<bits/stdc++.h>
using namespace std;
const int N=3000;
int f[N][N];
int n,m;
int ne[N],ver[N],head[N],idx,e[N];
void add(int u,int v,int w)
{
    ne[idx]=head[u];
    ver[idx]=v;
    head[u]=idx;
    e[idx]=w;
    idx++;
}

void dp(int x,int father)
{
    for(int i=head[x];i!=-1;i=ne[i])
    {
        int y=ver[i];
        if(y==father)continue;
        dp(y,x);
        for(int j=m;j>=0;j--)
        {
            for(int k=0;k+1<=j;k++)
            {
                f[x][j]=max(f[x][j],f[x][j-k-1]+f[y][k]+e[i]);
            }
        }
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dp(1,0);
    cout<<f[1][m]<<endl;
    return 0;
}

posted @ 2020-11-24 17:13  邦的轩辕  阅读(87)  评论(0编辑  收藏  举报