题解 | #打家劫舍(三)#

打家劫舍(三)

https://www.nowcoder.com/practice/58dad1054a0b41ab9b076e5bcc3160dc

树状dp,一般需要遍历树。方式是深度遍历。
这个题,节点用输入数值的下标来表示,如图所示:
alt f[i][0]表示 以i为根的子树,并且不包括节点i(最大值不包括节点的值)的最大值,该状态可以来自于左右子树(如果存在)的max(f[左子树][0], f[左子树][1])+max(f[右子树][0], f[右子树][1])
f[i][1]表示 以i为根的子树,并且包括节点i(最大值包括节点的值)的最大值,该状态可以来自于f[左子树][0]+f[右子树][0]+a[i]


#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int n;
//用邻接表存储二叉树
int h[N], e[N], ne[N], idx;

void add(int a, int b) // a是父节点 b是子节点
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int f[N][2];
int a[N];
void dfs(int u){
    f[u][1] = a[u];
    for(int i = h[u]; i!= -1; i = ne[i]){
        int j = e[i];
        dfs(j);
        f[u][1] += f[j][0]; // 父节点选了,子节点不能选了
        f[u][0] += max(f[j][0], f[j][1]);
    }
}
int main() {
    cin >> n;
    memset(h, -1, sizeof h);
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    int root = -1;
    for(int i = 1; i <= n; i++){
        int x;
        cin >> x;
        if(x==0) root = i;
        add(x, i);  // a_x 是a_i的父节点
    }
    dfs(root);
    cout << max(f[root][0], f[root][1]);
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
joe2333:怀念以前大家拿华为当保底的日子
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务