洛谷P2015 二叉苹果树

时间:2021-03-15 08:18:55

题目描述

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

二……二叉树……

二叉树大概只要DFS就可以了呀……写完树规才反应过来。

 /*by SilverN*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
struct edge{
int v,nxt;
int dis;
}e[mxn];
int hd[mxn],mct=;
void add_edge(int u,int v,int dis){
e[++mct].v=v;e[mct].nxt=hd[u];e[mct].dis=dis;hd[u]=mct;
return;
}
int n,q;
int f[mxn][mxn];
int num[mxn];
int w[mxn];
void DP(int u,int fa){
for(int i=;i<=num[u];i++){
f[u][i]=w[u];
}
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa)continue;
DP(v,u);
for(int j=num[u];j;j--){
for(int k=min(num[v],j-);k>=;k--){
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
}
}
}
return;
}
void Build(int u,int fa){
num[u]++;
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa)continue;
w[v]=e[i].dis;
Build(v,u);
num[u]+=num[v];
}
return;
}
int main(){
int i,j;
n=read();q=read();
int u,v,d;
for(i=;i<n;i++){
u=read();v=read();d=read();
add_edge(u,v,d);
add_edge(v,u,d);
}
Build(,);
DP(,);
printf("%d\n",f[][q+]);
return ;
}