![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; const int maxn = 100; int dp[maxn][maxn]; //dp[i][j]表示以i为根,保留j个点的最大权值。 int N,Q; int G[maxn][maxn]; int num[maxn]; //以i为根的树的节点个数。 //这里处理的时候要注意可以把边的权值压倒儿子节点。 void dfs(int u,int fa){ num[u] = 1; for(int v=1;v<=N;v++){ if(!G[u][v] || v == fa) continue; dfs(v,u); num[u] += num[v]; } for(int v=1;v<=N;v++){ //相当于分组k。 if(!G[u][v] || v == fa) continue; for(int i=num[u];i>0;i--){ //相对于下面的V -> 0 for(int j=1;j<i&&j<=num[v];j++) //枚举组k中的元素。 dp[u][i] = max(dp[u][i],dp[u][i-j]+dp[v][j]+G[u][v]); } } } /** f[k][v]表示前k组物品花费费用v能取得的最大权值 f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k} 分组背包一维数组的伪代码: for 所有的组k for v=V..0 for 所有的i属于组k f[v]=max{f[v],f[v-c[i]]+w[i]} **/ int main() { cin>>N>>Q; memset(G,0,sizeof(G)); memset(dp,0,sizeof(dp)); for(int i=1;i<N;i++){ int u,v,w; scanf("%d %d %d",&u,&v,&w); G[u][v] = G[v][u] = w; } dfs(1,-1); printf("%d ",dp[1][Q+1]); }