----------------
链接:Miku
----------------
这道题的dp还是先更新子节点,在更新父节点,不过问题就是怎样更新他们
我们定义ff[i][j]为第i个节点字数上共保留j条边的情况下最多的苹果数,对于每一个点,他保留的边必然是他直接保留的之前保留的边和他当前儿子保留的边的值的和加上这一条边的
边权,即ff[u][i]=max(ff[u][i],f[u][i−j−1]+ff[v][j]+e[i].w)( 1≤i≤min(q,son[u]),0≤j≤min(son[v],i−1) )
然后不断递归更新即可
----------------
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define ll long long const int maxn=105; using namespace std; int n,m,ff[maxn][maxn]; struct b{ int to; int ne; int w; }e[maxn*2]; int p; int head[maxn]; void add(int f,int to,int w){ p++; e[p].ne=head[f]; e[p].to=to; e[p].w=w; head[f]=p; } int x,y,z; int son[maxn]; void dfs(int now,int f){ for(int i=head[now];i;i=e[i].ne){ int v=e[i].to; if(v==f) continue; dfs(v,now); son[now]+=son[v]+1; for(int j=min(son[now],m);j;--j ){//我们就能取这些了 for(int k=min(son[v],j-1);k>=0;k--){//考虑一下怎么分配要保留的边 ff[now][j]=max(ff[now][j],ff[now][j-k-1]+ff[v][k]+e[i].w);//记得减一,不然我们就和这个v断开了联系 } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<n;++i){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); add(y,x,z); } dfs(1,-1);//根节点是谁不重要 printf("%d",ff[1][m]); return 0; }