洛谷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 dp[i][j]表示节点i保留j个枝条的最大苹果数 */ #include<iostream> #include<cstdio> using namespace std; #define maxn 110 int m,n,dp[maxn][maxn],num,head[maxn],sz[maxn],fa[maxn]; struct node{ int to,v,pre; }e[maxn*2]; void predfs(int father,int now){ sz[now]=1; fa[now]=father; for(int i=head[now];i;i=e[i].pre){ int to=e[i].to; if(to==father)continue; predfs(now,to); sz[now]+=sz[to]; } } void Insert(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].pre=head[from]; head[from]=num; } void dfs(int now){ for(int i=head[now];i;i=e[i].pre){ int to=e[i].to; if(to==fa[now])continue; dfs(to); for(int j=min(sz[now],m);j>=1;j--){ for(int k=min(j,sz[now]);k>=1;k--){ dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[to][k-1]+e[i].v); } } } } int main(){ scanf("%d%d",&n,&m); int x,y,z; for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); Insert(x,y,z); Insert(y,x,z); } predfs(0,1); dfs(1); printf("%d",dp[1][m]); }