树形DP

树形DP

算法简介

树形 DP 就是在树上做的 DP,大部分都是用子节点的信息推导出父节点的信息。在考虑问题可以被抽象出一个树状的模型的时候,可以尝试考虑一下树形DP。

简单来说就是结合了树的性质的动态规划(问树有哪些性质的人,自己去补)

树的表示

在树形 dp 中的树的形状各异,所以我习惯用vector来存储一个节点的所有子节点。用push_back方法去加入一个子节点,这将比自己实现的左子树右孩子的写法更安全可靠。(作为代价,可能会牺牲一点点的效率。)

题目示例:POJ2342

题意:

给n个人参加聚会,每个人有个活跃度,他们之间有上司和下属关系,如果上司参加了则==直系==下属不去参加,求最大活跃度(上司和下属关系都是直接关系,不需要考虑间接的情况)。

输入:

雇员编号从1到N。第一行的输入包含一个数字N. 1 <= N <=6000。接下来的N行包含相应员工的欢乐度。欢乐的评级是一个整数的范围从128到127 -。在去n - 1行描述一个主管关系树。每一行的树规范都有形式:
L K
这意味着,第k个员工是l个员工的直接主管。输入结束与行
0 0

输入示例:

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0

构成的编号树即为

graph LR  
5-->3
5-->4
3-->1
3-->2
4-->6
4-->7
思路:

状态转移方程:

dp[rt][0]:以rt为根的树,rt本身不来的最大活跃度  
dp[rt][1]:以rt为根的树,rt本身来的最大活跃度

dp[rt][1] = dp[rt][1] + dp[sonI][0];      //上司来,则下属不能来 
dp[rt][0] = dp[rt][0] + max(dp[sonI][0],dp[sonI][1]);  //上司不来,下属可来可不来

初始化:将所有员工全部存入一个树中,上司为根,下属为子节点。

遍历:从根节点开始进行DFS,并且按照状态转移方程来不断更新DP数组

void dfs(int rt){
    vis[rt] = 1;
    for (int i = 1; i <= n; ++i){
        if(!vis[i] && father[i] == rt){    //下属
            dfs(i);
            dp[rt][1] += dp[i][0];              //上司来,则下属不能来
            dp[rt][0] += max(dp[i][0],dp[i][1]);    //上司不来,下属可来可不来
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值