题目描述
有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点)
这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1。
我们用一根树枝两端连接的结点的编号来描述一根树枝的位置。下面是一颗有4个树枝的树
2 5
\ /
3 4
\ /
1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。给定需要保留的树枝数量,求出最多能留住多少苹果。
分析
典型的树上dp问题,记
fij
f
i
j
为根为
i
i
的树中选择条边最多能保留的果子数目
fij=max(fsonl,j−1+wi,sonl,fsonr,j−1+wi,sonr,fsonl,k+fsonr,j−2−k+wi,sonl+wi,sonr)
f
i
j
=
m
a
x
(
f
s
o
n
l
,
j
−
1
+
w
i
,
s
o
n
l
,
f
s
o
n
r
,
j
−
1
+
w
i
,
s
o
n
r
,
f
s
o
n
l
,
k
+
f
s
o
n
r
,
j
−
2
−
k
+
w
i
,
s
o
n
l
+
w
i
,
s
o
n
r
)
其中
k
k
的范围为
#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
char ch = getchar();
int x = 0 , f = 1 ;
while( !isdigit( ch ) )
if( ch == '-' ) f = -1 , ch = getchar();
else ch = getchar();
while( isdigit( ch ) )
x = (ch - '0') + x * 10 , ch = getchar();
return x * f;
}
const int maxn = 100 + 5;
struct edge{
int v , w , nxt;
}e[maxn * 2];
int f[maxn][maxn] , head[maxn] , _t = 0 , M = 0;
inline void cmax( int &a , int b ){
a = a > b ? a : b;
}
void addedge( int u , int v , int w ){
e[_t].v = v , e[_t].w = w , e[_t].nxt = head[u] , head[u] = _t++;
}
void dfs( int u , int fa ){
int son[2][2] , cnt = 0 , v;
erep( i , u ){
v = e[i].v;
if( v == fa ) continue;
son[cnt][0] = v , son[cnt][1] = e[i].w; ++cnt;
dfs( v , u );
}
if( cnt == 0 ) return;
rep( j , 1 , M ){
cmax( f[u][j] , f[ son[0][0] ][j - 1] + son[0][1] );
cmax( f[u][j] , f[ son[1][0] ][j - 1] + son[1][1] );
if( j >= 2 )
rep( k , 0 , j - 2 )
cmax( f[u][j] , f[ son[0][0] ][k] + f[ son[1][0] ][j - 2 - k] + son[0][1] + son[1][1] );
}
}
int main(){
memset( head , 0xff , sizeof head );
int N = _read(); M = _read();
int u , v , w;
rep( i , 1 , N - 1 ){
u = _read() , v = _read() , w = _read();
addedge( u , v , w );
addedge( v , u , w );
}
dfs( 1 , 0 );
cout << f[1][M] << endl;
return 0;
}