题意:
给定n个顶点的树,点1为根,
每个点都是一个怪物,第i个怪物有a(i)的血量,
如果你要消灭第x个怪物,需要花费a(x)+sum{a(v)}的代价,其中v是与x相连的儿子。
现在你可以进行k次操作,一次操作可以直接删掉某个怪物而不需要代价,
问对于k=[0,n],消灭所有怪物需要的最少代价是多少。
数据范围:n<=2e3
解法:
显然存在树形依赖,
令d[0/1][i][j]表示:当前点是否保留,以i为根的子树保留j个点的最小花费.
树形dp一下即可,需要用size优化将复杂度变为O(n^2).
转移方程见代码
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e3+5;
vector<int>g[maxm];
int d[2][maxm][maxm];
int sz[maxm];
int a[maxm];
int n;
void dfs(int x){
sz[x]=1;
for(int i=0;i<=n;i++){
d[0][x][i]=d[1][x][i]=1e18;
}
d[1][x][1]=a[x];//保留
d[0][x][0]=0;//删掉
for(int v:g[x]){
dfs(v);
for(int i=sz[x];i>=0;i--){
for(int j=0;j<=sz[v];j++){
d[0][x][i+j]=min(d[0][x][i+j],d[0][x][i]+d[0][v][j]);
d[0][x][i+j]=min(d[0][x][i+j],d[0][x][i]+d[1][v][j]);
d[1][x][i+j]=min(d[1][x][i+j],d[1][x][i]+d[0][v][j]);
d[1][x][i+j]=min(d[1][x][i+j],d[1][x][i]+a[v]+d[1][v][j]);//xv都不删,则需要多花费a[v].
}
}
sz[x]+=sz[v];
}
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++)g[i].clear();
for(int i=2;i<=n;i++){
int fa;cin>>fa;
g[fa].push_back(i);
}
for(int i=1;i<=n;i++){
cin>>a[i];
}
dfs(1);
for(int i=0;i<=n;i++){
cout<<min(d[0][1][n-i],d[1][1][n-i])<<' ';
}
cout<<endl;
}
signed main(){
ios::sync_with_stdio(0);
int T;cin>>T;
while(T--){
solve();
}
return 0;
}