洛谷 P2015 二叉苹果树

传送门

给一个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;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/11696701.html