规划问题在于怎么选,选不选

树形dp关键在于节点选不选,由此分出两种状态,利用树形结构将要求的值遍历求解,集中在根节点

没有上司的舞会

没有直接上司大家都高兴,求怎么安排大家最高兴

状态表示

每个点分为两种状态,在当前遍历到点所有子节点最大值的那种选法中,这个点两种状态的最大值

注意到不是选不选这个点的最大值,因为没考虑到其父节点,只有子节点的最大值已知情况的,其两种情况分别的最大值

状态计算

dfs遍历树,f[i][0] 存下没有第i点的情况的当前树的最大值 and f[i][1] 存下有第i点的当前树的最大值 f[i][0] += max(f[j][0], f[j][1] 所有子树互不干扰,其所有子节点的值相加就是当前最大值 f[i][1] += f[j][0] 当前值确定选,那么直接下属不选

实现

#include <iostream>
#include <algorithm>
#include <cstring>
 
using namespace std;
 
const int N = 6010;
 
int h[N], e[N], ne[N], idx;
 
int H[N];
//注意没有告知根节点,要加bool数组求
bool father[N];
int f[N][N];
 
void add(int a, int b)
{
    e[idx] = b; ne[idx] = h[a]; h[a] = idx ++;   
}
 
void dfs(int u)
{
    //每个人自己参加幸福程度就加1
    f[u][1] = H[u];
    
    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        dfs(j);
        
        f[u][0] += max(f[j][0], f[j][1]);
        f[u][1] += f[j][0];
    }
}
 
int main()
{
    int n;
    cin >> n;
    
    for(int i = 1; i <= n; i ++)
        cin >> H[i];
        
    memset(h, -1, sizeof h);
    
    for(int i = 0; i < n - 1; i ++)
    {
        int a, b;
        cin >> a >> b;
        
        father[a] = true;
        
        add(b, a);
    }
    
    int root = 1;
    while(father[root]) root ++;
    
    //从根节点开始遍历
    dfs(root);
    
    cout << max(f[root][0], f[root][1]) << endl;
    
    return 0;
}