标签:print 代码 ring class mat 背包问题 cst 滚动数组 sum
题目大意:给出一棵树,叶子结点增加一定的权值,经过减少一定的权值,求在总权值\(\geq0\)的情况下可以到达的叶子结点最多的数量.
树上的背包问题
在树上做背包,每搜到一个点就更新一遍,注意滚动数组,倒序
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 3005;
const int INF = 1147483640;
struct Edge{
int to, next, val;
}e[N];
int n, m, cnt;
int son[N], head[N], money[N], f[N][N], sz[N];
inline void addedge(int x, int y, int z){
e[++cnt].to = y;
e[cnt].val = z;
e[cnt].next = head[x];
head[x] = cnt;
return;
}
int dfs(int x){
if(x > n - m){
f[x][1] = money[x];//如果是叶子结点,改变初始值
return sz[x] = 1;
}
for(int i = head[x], v, l_sum = 0; i; i = e[i].next){
v = e[i].to;
l_sum = dfs(v);
sz[x] += l_sum;
for(int j = sz[x]; j; --j)//这个点包含的客户,每次都更新下
for(int k = 1; k <= l_sum; ++k){//f[v][k]中的k限制于sz[v]
if(j - k < 0 ) break;
f[x][j] = std::max(f[x][j], f[x][j - k] + f[v][k] - e[i].val);
}
}
return sz[x];
}
int main(){
scanf("%d %d", &n, &m);
for(int i = 1; i <= n - m; ++i){
scanf("%d", &son[i]);
for(int j = 1, x, y; j <= son[i]; ++j){
scanf("%d %d", &x, &y);
addedge(i, x, y);
}
}
for(int i = n - m + 1; i <= n; ++i)
scanf("%d", &money[i]);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
f[i][j] = -INF;
}
}
dfs(1);
for(int i = m; i; --i){
if(f[1][i] >= 0){
printf("%d", i);
break;
}
}
return 0;
}
标签:print 代码 ring class mat 背包问题 cst 滚动数组 sum
原文地址:https://www.cnblogs.com/LMSH7/p/9531917.html