|
|
更好的阅读体验:https://www.cnblogs.com/To-Carpe-Diem/p/19359481
思路首先,这个题目的建图太抽象了,需要好好理解一下。 然后我们考虑树上背包。 我们定义 $f_{u, j}$ 表示,在 $u$ 这颗子树内选择 $j$ 个叶子节点的最大收益(叶子点权和 $-$ 需要的边权和)。 那么我们显然有转移: $ f_{u, j} = \max(f_{u, j}, f_{u, j - k} + f_{v, k} + w(u, v)) $ 显然如果你选择了 $v$ 这个子树所产生的收益,那么你就必须承担 $u - v$ 这条边的代价。 然后随便作一些上下界优化即可。
代码
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN = 3005;
int n, m;
struct node{
int u, w;
};
vector<node> e[MAXN];
int a[MAXN], sz[MAXN];
int f[MAXN][MAXN];
void dfs(int u){
f[u][0] = 0;
if(e[u].empty()){
f[u][1] = a[u];
return;
}
for(int i = 0;i < e[u].size();i ++){
int v = e[u][i].u, w = e[u][i].w;
dfs(v);
for(int j = min(m, sz[u]);j >= 1;j --){
for(int k = max(0, j - sz[u] - sz[v]);k <= min(j, sz[v]);k ++){
f[u][j] = max(f[u][j], f[u][j - k] + f[v][k] - w);
}
}
}
}
void dfs2(int u){
sz[u] = 1;
for(int i = 0;i < e[u].size();i ++){
int v = e[u][i].u;
dfs2(v);
sz[u] += sz[v];
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
memset(f, -0x3f3f3f3f, sizeof(f));
cin >> n >> m;
for(int i = 1;i <= n - m;i ++){
int k; cin >> k;
for(int j = 1;j <= k;j ++){
int c, w; cin >> c >> w;
e[i].push_back({c, w});
}
}
for(int i = n - m + 1;i <= n;i ++){
cin >> a[i];
}
dfs2(1);
dfs(1);
int ans = 0;
for(int i = m;i >= 0;i --){
if(f[1][i] >= 0){
ans = i;
break;
}
}
cout << ans << '\n';
return 0;
}
题目1189 有线电视网
AAAAAAAAAA
6
评论
2026-02-04 20:46:02
|