B. Work Group 树形DP
B. Work Group 树形DP
题目大意:
给你一棵树,每一个节点都有一个权值,你可以选择一个集合,要求这个集合内每一个点它的所有儿子节点都是偶数,问这个集合最大权值是多少?
题解:
很自然的一个定义 \(dp[u][0]\) 表示以 \(u\) 为根节点选择了偶数个节点, \(dp[u][1]\) 表示以 \(u\) 为根节点选择了奇数个节点,但是要注意的是这个 \(dp[u][0]\) 也是一个合法状态,比如一个节点 \(u\) 连了五个叶子节点,那么 \(dp[u][0]\) 就等于前四个较大权值的和。
那么转移方程就是
\(res0 = dp[u][0],res1 = dp[u][1]\)
\(dp[u][0] = max(res0+dp[v][0],res1+dp[v][1])\)
\(dp[u][1] = max(res0+dp[v][1],res1+dp[v][0])\)
但是这样做要注意一个初始化问题,应该首先初始化 \(dp[u][1] = -inf\) 而不是 \(dp[u][1] = a[u]\)
因为如果令 \(dp[u][1] = a[u]\) ,那么对于 \(dp[u][1]\) 的转移会出现错误,如果有三个点,1 - 2 - 3,那么\(dp[u][3] = a[3]\) ,那么对于2节点转移就会出现错误, \(dp[2][0] = a[2]+a[3]\) 这样的情况是非法的。
所以要避免这个情况,首先要从儿子节点转移,然后再从本身转移。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
void add(int u,int v){
    ++cnt,to[cnt] = v,nxt[cnt] = head[u],head[u] = cnt;
}
int a[maxn];
ll dp[maxn][2];
void dfs(int u){
    dp[u][1] = -inf64;
    for(int i=head[u];i;i=nxt[i]){
        int v = to[i];
        dfs(v);
        ll res1 = dp[u][1],res0 = dp[u][0];
        dp[u][0] = max(res0+dp[v][0],res1+dp[v][1]);
        dp[u][1] = max(res1+dp[v][0],res0+dp[v][1]);
    }
    dp[u][1] = max(dp[u][1],dp[u][0]+a[u]);
//    printf("u = %d [0] = %lld [1] = %lld\n",u,dp[u][0],dp[u][1]);
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++){
        scanf("%d%d",&x,&a[i]);
        if(x!=-1) add(x,i);
    }
    dfs(1);
    printf("%lld\n",max(dp[1][0],dp[1][1]));
    return 0;
}
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号