设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示以
i
i
i 节点保留
j
j
j 条树枝最多苹果数量。
易得:
∑
j
=
2
m
∑
k
=
1
,
k
<
j
s
z
[
v
]
d
p
[
u
]
[
j
]
=
m
a
x
(
d
p
[
u
]
[
j
]
,
d
p
[
u
]
[
j
−
k
]
+
d
p
[
v
]
[
k
]
\sum\limits_{j=2}^m \sum\limits_{k=1,k<j}^{sz[v]}dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]
j=2∑mk=1,k<j∑sz[v]dp[u][j]=max(dp[u][j],dp[u][j−k]+dp[v][k] 。
注意:这里的二维其实相当于普通背包的一维,所以
j
j
j 的枚举应该倒序。
#include<bits/stdc++.h>using ll =longlong;intmain(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);int n, q;
std::cin >> n >> q;++q;
std::vector<std::tuple<int,int,int>>e((n +1)<<1);
std::vector<int>head(n +1);int cnt =0;auto add =[&](int u,int v,int w){
e[++cnt]={v, w, head[u]}, head[u]= cnt;};for(int i =1; i < n;++i){int u, v, w;
std::cin >> u >> v >> w;add(u, v, w);add(v, u, w);}
std::vector<std::vector<int>>dp(n +1, std::vector<int>(q +1));
std::vector<int>sz(n +1);
std::function<void(int,int,int)> dfs =[&](int u,int f,int m){
sz[u]=1;for(int i = head[u]; i;){auto[v, w, nxt]= e[i];if(f xor v){
dp[v][1]= w;dfs(v, u, m);
sz[u]+= sz[v];for(int j = m; j >1;--j){for(int k =1; k <= sz[v]and k < j;++k){
dp[u][j]= std::max(dp[u][j], dp[u][j - k]+ dp[v][k]);}}}
i = nxt;}};dfs(1,0, q);
std::cout << dp[1][q];return0;}
设
d
p
[
u
]
[
j
]
dp[u][j]
dp[u][j] 为
u
u
u 节点 染
j
j
j 个为黑色最大效益。
易得:
∑
j
=
0
m
i
n
(
k
,
s
z
[
u
]
)
∑
l
=
0
m
i
n
(
s
z
[
v
]
,
l
)
d
p
[
u
]
[
j
]
=
m
a
x
(
d
p
[
u
]
[
j
]
,
d
p
[
u
]
[
j
−
l
]
+
d
p
[
v
]
[
l
]
+
v
a
l
\sum\limits_{j=0}^{min(k,sz[u])} \sum\limits_{l=0}^{min(sz[v],l)}dp[u][j] = max(dp[u][j], dp[u][j-l]+dp[v][l]+val
j=0∑min(k,sz[u])l=0∑min(sz[v],l)dp[u][j]=max(dp[u][j],dp[u][j−l]+dp[v][l]+val 。
v
a
l
val
val 即是很常见的计算贡献的思想。
考虑一条边把树分成两部分树
A
A
A ,树
B
B
B ,树
B
B
B 选择
l
l
l 个点染黑色,那么另外
k
−
l
k - l
k−l 个黑色节点即在树
A
A
A,那么这条边就会被计算
l
×
(
k
−
l
)
l \times (k-l)
l×(k−l) 次,贡献即为
l
×
(
k
−
l
)
×
w
l\times(k-l)\times w
l×(k−l)×w 。树
B
B
B 的另外
s
z
[
B
]
−
l
sz[B]-l
sz[B]−l 个节点即为白色,那么另外
n
−
k
−
(
s
z
[
B
]
−
l
)
n-k-(sz[B]-l)
n−k−(sz[B]−l) 个白色节点即在树
A
A
A ,所以该边白色贡献为
(
s
z
[
B
]
−
l
)
×
(
n
−
k
−
(
s
z
[
B
]
−
l
)
)
∗
w
(sz[B] - l) \times (n - k - (sz[B] - l)) * w
(sz[B]−l)×(n−k−(sz[B]−l))∗w 。
同样倒序枚举
j
j
j 。
#include<bits/stdc++.h>using ll =longlong;intmain(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);int n, k;
std::cin >> n >> k;
std::vector<std::tuple<int, ll,int>>e((n +1)<<1);
std::vector<int>head(n +1);int cnt =0;auto add =[&](int u,int v, ll w){
e[++cnt]={v, w, head[u]}, head[u]= cnt;};for(int i =1; i < n;++i){int u, v;
ll w;
std::cin >> u >> v >> w;add(u, v, w);add(v, u, w);}
std::vector<std::vector<ll>>dp(n +1, std::vector<ll>(k +1,-1));
std::vector<int>sz(n +1);
std::function<void(int,int)> dfs =[&](int u,int f){
sz[u]=1;
dp[u][0]= dp[u][1]=0;for(int i = head[u]; i;){auto[v, w, nxt]= e[i];if(v xor f){dfs(v, u);
sz[u]+= sz[v];for(int j = std::min(k, sz[u]); j >=0;--j){for(int l =0; l <= std::min(sz[v], k);++l){if(dp[u][j - l]not_eq-1and j >= l){
ll val =1ll* l *(k - l)* w +1ll*(sz[v]- l)*(n - k -(sz[v]- l))* w;
dp[u][j]= std::max(dp[u][j], dp[u][j - l]+ dp[v][l]+ val);}}}}
i = nxt;}};dfs(1,0);
std::cout << dp[1][k];return0;}