如形の博客

:::info{open} 设计状态:用 dpu,0/1dp_{u,0/1} 表示以 uu 为根的子树的最大快乐指数。

答案max{dproot,1,dproot,0}\max\{dp_{root,1},dp_{root,0}\}。 :::

P1352 没有上司的舞会#

若如图所示,当前 dfs 至点 uu,则转移方程如下: dpu,0dpu,0+max(dpv,0,dpv,1)dp_{u,0}\leftarrow dp_{u,0}+\max(dp_{v,0},dp_{v,1}) dpu,1dpu,1+dpv,0dp_{u,1}\leftarrow dp_{u,1}+dp_{v,0}

1

所以可以写出以下代码:

#include<bits/stdc++.h>
using namespace std;
int n,r[6005],in[6005],rt,dp[6005][2];
vector<int>g[6005];
void dfs(int u){
    for(int v:g[u]){
        dfs(v);
        dp[u][0]+=max(dp[v][0],dp[v][1]);
        dp[u][1]+=dp[v][0];
    }
    dp[u][1]+=r[u];
}
int main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>r[i];
    }
    for(int i=1;i<n;++i){
        int u,v;
        cin>>u>>v;
        g[v].push_back(u);
        in[u]=1;
    }
    for(int i=1;i<=n;++i){
        if(!in[i]){
            rt=i;
            break;
        }
    }
    dfs(rt);
    cout<<max(dp[rt][0],dp[rt][1];
}
cpp

P2016 [SEERC 2000] 战略游戏#

在开始是初始化一下 dpu,0/1dp_{u,0/1} 即可。 :::error[为什么不需要初始化 dpdp 为无穷大]{open} 在 dfs 中会遍历每个子节点,所以初始化子节点即可,树形 DP 无需 memset dpdp 数组。 :::

#include<bits/stdc++.h>
using namespace std;
int n,in[5005],dp[5005][2],rt;
vector<int>g[5005];
void dfs(int u){
    dp[u][0]=0;
    dp[u][1]=1;
    for(int v:g[u]){
        dfs(v);
        dp[u][0]+=dp[v][1];
        dp[u][1]+=min(dp[v][0],dp[v][1]);
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        int u,k,v;
        cin>>u>>k;
        u++;
        for(int j=1;j<=k;++j){
            cin>>v;
            v++;
            g[u].push_back(v);
            in[v]=1;
        }
    }
    for(int i=1;i<=n;++i){
        if(!in[i]){
            rt=i;
            break;
        }
    }
    dfs(rt);
    cout<<min(dp[rt][0],dp[rt][1]);
    return 0;
}
cpp

P1122 最大子树和#

1

#include<bits/stdc++.h>
using namespace std;
int n,a[16005],dp[16005],ans=INT_MIN;
vector<int>g[16005];
void dfs(int u,int fa){
    dp[u]=a[u];
    for(int v:g[u]){
        if(v!=fa){
            dfs(v,u);
            dp[u]+=max(0,dp[v]);
        }
    }
}
int main(){
    cin>>n;
    for(int i=1;i<=n;++i)cin>>a[i];
    for(int i=1;i<n;++i){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    for(int i=1;i<=n;++i){
        ans=max(dp[i],ans);
    }
    cout<<ans;
    return 0;
}
cpp

P2585 [ZJOI2006] 三色二叉树#

笔记——树形动态规划
https://blog.rusin7.com/article/notes-of-dp-on-trees
Author 如形
Published at June 7, 2026
Comment seems to stuck. Try to refresh?✨