Work Group

Work Group

https://ac.nowcoder.com/acm/problem/110906

题意:
有一颗n个节点并且以1为根的树,每一个节点有一个权值,你可以选择一些节点组成工作组,工作中中的每一个节点他的子树上的节点在工作组的数目为偶数(不包括自己),求工作组的最大权值为多少(工作组的权值等于工作组中每个节点的权值之和)?

思路:
树状dp
dp[v][0/1]表示第v个节点在满足条件时该子树在工作组的个数为偶数/奇数的最大权值。
首先初始化:(一开始不包括v节点)
dp[v][0]=0;
dp[v][1]=-inf;(极小值表示不存在)
然后加入子树u:
dp[v][0]=max(dp[v][1]+dp[u][1],dp[v][0]+dp[u][0]);(奇数+奇数=偶数,偶数+偶数=偶数)
dp[v][1]=max(dp[v][1]+dp[u][0],dp[v][0]+dp[u][1]);(奇数+偶数=奇数,偶数+奇数=偶数)
最后加入v节点:
dp[v][0]不变,因为加入v节点成偶数则需要子树共有奇数个节点,不符合条件,所以偶数个一定不包括根节点。
dp[v][1]=max(dp[v][0]+val[v],dp[v][1]);

代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <iostream>

using namespace std;

typedef long long ll;
const ll inf=998244353;
const int N=200005;

ll val[N], dp[N][2];
vector<int> g[N];

void dfs(int v)
{
    dp[v][0]=0;
    dp[v][1]=-inf;
    for(int i=0;i<g[v].size();i++)
    {
        int u=g[v][i];
        dfs(u);
        ll tmp=max(dp[v][0]+dp[u][0],dp[v][1]+dp[u][1]);   //对计算后的dp[v][0]先保存,防止对计算dp[v][1]造成影响。
        dp[v][1]=max(dp[v][0]+dp[u][1],dp[v][1]+dp[u][0]);
        dp[v][0]=tmp;
    }
    dp[v][1]=max(dp[v][1],dp[v][0]+val[v]);
}

int main()
{
    int n;
    scanf("%d",&n);
    ll sum=0, mi=inf;
    for(int i=1;i<=n;i++)
    {
        ll a;
        scanf("%lld%lld",&a,&val[i]);
        if(a!=-1)
        {
            g[a].push_back(i);
        }
    }
    dfs(1);
    cout << max(dp[1][0],dp[1][1]) << endl;
    return 0;
}
每日一题题解 文章被收录于专栏

写题解

全部评论

相关推荐

整顿职场的柯基很威猛:这种不可怕,最可怕的是夹在一帮名校里的二本选手,人家才是最稳的。
点赞 评论 收藏
分享
10-15 15:00
潍坊学院 golang
跨考小白:这又不是官方
投递拼多多集团-PDD等公司10个岗位
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务