题目大意:
一颗苹果树上,每条边都对应了一个权值,最后留下包括root : 1在的含有 m 条边的子树 , 希望留下的子树中权值之和最大
这里保留m条边,我们可以看作是保留了 m + 1 个点
令dp[u][j] 表示 u 为根的子树中包含了j个点的子树中得到的权值最大和
状态转移方程:
dp[u][j] = max{dp[v][k] + dp[u][j-k] + e[i].d} v为u的子节点 j>k>=1 , 1<=j<=m+1
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 const int N = 105; 6 int val[N] , first[N] , k , dp[N][N]; 7 8 struct Edge{ 9 int y , next , d; 10 }e[N<<1]; 11 12 void add_edge(int x, int y , int d) 13 { 14 e[k].y = y , e[k].d = d , e[k].next = first[x]; 15 first[x] = k++; 16 } 17 18 void dfs(int u , int fa , int m) 19 { 20 for(int i = first[u] ; i!=-1 ; i=e[i].next){ 21 int v = e[i].y; 22 if(v == fa) continue; 23 dfs(v , u , m); 24 for(int j = m ;j>=1; j--) 25 for(int k=1 ; k<j ; k++) 26 dp[u][j] = max(dp[u][j] , dp[v][k] + dp[u][j-k] + e[i].d); 27 } 28 } 29 30 int main() 31 { 32 // freopen("a.in" , "r" , stdin); 33 int n,m,x,y,d; 34 while(scanf("%d%d" , &n , &m)==2) 35 { 36 memset(first , -1 , sizeof(first)); 37 k = 0; 38 for(int i=1 ; i<n ; i++){ 39 scanf("%d%d%d" , &x , &y , &d); 40 add_edge(x , y , d); 41 add_edge(y , x , d); 42 } 43 44 memset(dp , 0 , sizeof(dp)); 45 dfs(1 , -1 , m+1); 46 47 printf("%d " , dp[1][m+1]); 48 } 49 return 0; 50 }