ICPC2020南京M.Monster

写在前面

大概是高中退役之后第一次写写题解,当然要从基础写起,因为变得更菜了,所以只能写写更水的题目了

题目链接

ICPC南京M

题解

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
*/
posted @ 2020-12-25 20:22  zzzzx  阅读(192)  评论(2编辑  收藏  举报