luogu P2015 二叉苹果树

题目描述

有一棵苹果树,如果树枝有分叉,一定是分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

树形dp+背包
f[i][j]表示以i为根的子树中选取j条边的最大价值

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn = 1007;
inline int read() {
    int x=0,f=1;
    char c=getchar() ;
    while(c<'0'||c>'9') {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
        x=x*10+c-'0',c=getchar();
    return x*f;
}
struct node {
    int v,next,w;
}edge[maxn];
int head[maxn],num=0;
inline void add_edge(int u,int v,int w) {
    edge[++num].v=v;edge[num].w=w;edge[num].next=head[u];head[u]=num;
}
int n,k;
int dp[maxn][maxn]; 
void dfs(int x,int f) {
    for(int i=head[x];i;i=edge[i].next) {
        int v=edge[i].v;
        //dp[v][1]=edge[i].w;
        if(v==f)continue;
        dfs(v,x);
        for(int j=k;j>=1;j--) 
            for(int p=0;p<j;p++) 
                dp[x][j]=max(dp[x][j],dp[v][p]+dp[x][j-p-1]+edge[i].w); //从子树v中选取p条
				//再从其他子树中选取j-p-1条,加上连接v与x的苹果数. 
    }
}
int main () { 
    n=read(),k=read();
    for(int a,b,c,i=1;i<n;++i) {
        a=read(),b=read(),c=read();
        add_edge(a,b,c);
        add_edge(b,a,c);
    }
    dfs(1,0);
    printf("%d
",dp[1][k]);
    return 0;
}
    
原文地址:https://www.cnblogs.com/sssy/p/7791512.html