原题链接

考察:树形dp

求保留边后树边权值最大和

思路:

        因为选择子节点必须选择父节点,对于一个父节点u,它的两个子节点v1,v2.v1可以选择m条边,那么v2就能选择q-m-1-1条边对于每个一个树的结点,都能这样枚举,所以动态转移方程为f[u][j] = max(f[u][j],f[u][j-k-1]+f[v2][k]+road[i].w) u结点的子结点看成分组背包里的各个小组.一个小组只能选择k个,剩余小组选择剩下的.

        此数组实际省略了第几组的信息,所以需要体积需要倒序循环.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 110;
 7 struct Road{
 8     int fr,to,ne,w;
 9 }road[N<<1];
10 int h[N],idx,q,n,f[N][N];
11 void add(int a,int b,int c)
12 {
13     road[idx].w = c,road[idx].to=b,road[idx].fr = a,road[idx].ne = h[a],h[a] = idx++;
14 }
15 void dfs(int u,int fa)
16 {
17     for(int i=h[u];i!=-1;i=road[i].ne)
18     {
19         int v = road[i].to;
20         if(v==fa) continue;
21         dfs(v,u);
22         for(int j=q;j>=0;j--)
23           for(int k=0;k<j;k++)
24             f[u][j] = max(f[u][j],f[v][k]+f[u][j-1-k]+road[i].w);
25     }
26 }
27 int main()
28 {
29     scanf("%d%d",&n,&q);
30     memset(h,-1,sizeof h);
31     for(int i=1;i<n;i++)
32     {
33         int a,b,c; scanf("%d%d%d",&a,&b,&c);
34         add(a,b,c); add(b,a,c);
35     }
36     dfs(1,-1);
37     printf("%d\n",f[1][q]);
38     return 0;
39 }