題目描述
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有隻有1個兒子的結點)
這棵樹共有N個結點(葉子點或者樹枝分叉點),編號爲1-N,樹根編號一定是1。
我們用一根樹枝兩端連接的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹
2 5
\ /
3 4
\ /
1
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。給定需要保留的樹枝數量,求出最多能留住多少蘋果。
分析
典型的樹上dp問題,記 爲根爲 的樹中選擇 條邊最多能保留的果子數目
其中 的範圍爲
#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;
}