ICPC2020南京M.Monster
写在前面
大概是高中退役之后第一次写写题解,当然要从基础写起,因为变得更菜了,所以只能写写更水的题目了
题目链接
题解
f(i,j,k)节点i 当前节点是否存活 i及子树内的节点存活数 该状态的所以需要的最小能量值
代码
#include<bits/stdc++.h>
#define rep(a,b,c) for(int a = b;a <= c; ++ a)
#define pc putchar
#define gc getchar()
#define LL long long
using namespace std;
inline int read() {
int x = 0;
char c = gc;
while(c < '0' || c > '9') c = gc;
while(c <= '9' && c >= '0') x = x * 10 + c - '0',c = gc;
return x;
}
const LL INF = 1e18;
const int maxn = 4007;
int n,m;
LL p[maxn],hp[maxn];
vector<int>son[maxn];
LL f[maxn][2][maxn]; //x alive remain
//if fa d son a no
//if fa a son d no
//if fa d son d no
//if son a fa a yes
int sonsize[maxn];
void dfs(int x) {
int k = son[x].size();
f[x][0][0] = 0;
f[x][1][1] = hp[x];
sonsize[x] = 1;
for(int i = 0; i < k;++ i) {
int v = son[x][i];
dfs(v);
int kk = son[v].size();
for(int j = sonsize[x];j >= 0;-- j)
for(int k = sonsize[v];k >= 0 ; -- k) {
f[x][1][j + k] = std::min(f[x][1][j + k],f[x][1][j] + min(f[v][0][k],f[v][1][k] + hp[v]));
f[x][0][j + k] = std::min(f[x][0][j + k],f[x][0][j] + min(f[v][0][k],f[v][1][k]));
}
sonsize[x] += sonsize[v];
}
}
int main() {
int T = read();
while(T --) {
n = read();
rep(i,1,n)son[i].clear();
rep(i,1,n) rep(j,0,n) f[i][0][j] = f[i][1][j] = INF;
for(int i = 2;i <= n; ++ i) { p[i] = read();son[p[i]].push_back(i); }
rep(i,1,n) hp[i] = read();
dfs(1);
for(int i = n;i >= 0;-- i) {
printf("%lld ",std::min(f[1][1][i],f[1][0][i]));
}
puts("");
}
}
/*
3
5
1 2 3 4
1 2 3 4 5
9
1 2 3 4 3 4 6 6
8 4 9 4 4 5 2 4 1
12
1 2 2 4 5 3 4 3 8 10 11
9 1 3 5 10 10 7 3 7 9 4 9
*/