给一个n个节点的树,边带权值,要求保留q条连通根节点1的边,求这q条边最大总权值是多少。
算是一个树形背包的模板题,可以将边权转化为子节点的点权来考虑分组背包,注意本题中如果要选子节点,其父节点也必须被选。
ps.没注意分组背包的写法wa了一发,
第一次for为枚举子树
第二次for为枚举当前节点的限重,也就是背包限重,注意01背包和完全背包区别。
第三次for枚举子树重量。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; int n,q; int head[110],to[210],nxt[210],len[210],tot,siz[110]; int f[110][110]; void add(int u,int v,int w) {to[++tot]=v;nxt[tot]=head[u];len[tot]=w;head[u]=tot;} void dfs(int u,int rt,int w){ siz[u]=1; for(int i=head[u];i;i=nxt[i]){ if(to[i]==rt) continue; dfs(to[i],u,len[i]); siz[u]+=siz[to[i]]; } f[u][1]=w; for(int i=head[u];i;i=nxt[i]) for(int j=min(q,siz[u]);j>=0;j--) for(int k=1;k<j;k++) f[u][j]=max(f[u][j],f[u][j-k]+f[to[i]][k]); } int main(){ scanf("%d%d",&n,&q); for(int i=1,u,v,w;i<n;i++){ scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } q++; dfs(1,0,0); printf("%d ",f[1][q]); return 0; }