poj2342—树形dp

华电北风吹
天津大学认知计算与应用重点实验室
日期:2015/9/15

poj上一道与动态规划特别像的题目(http://poj.org/problem?id=2342),一个公司要出席一些人员,每个人对应一个活跃度,要求是不能存在直属关系,活跃度最大。参考了别人的博客,很多人说这个是树形动态规划,我个人感觉应该划分到分治法里面(不存在重叠子问题)。
下面是我修改后的代码,采用递归的思路。例如计算根节点的最大活跃度,需要判断根节点的每一个子节点,根节点出席的话就把子节点不出席时候的活跃度相加,如果根节点不出席,就把所有根节点出席和不出席中活跃度最大的加起来,依次递归。其中,leader保存每个节点的直属leader,dp[i][0/1] 保存当前节点子树出席和不出席的活跃度。
C++ code:

#include<iostream>
#include<fstream>
#include<algorithm>

using namespace std;

#define maxn 100

int n;
int dp[maxn][2], leader[maxn];                         //dp[i][0]0表示不去,dp[i][1]1表示去了

void tree_dp(int node)
{
    int i;
    for (i = 1; i <= n; i++)
    {
        if (leader[i] == node)          //i为下属
        {
            tree_dp(i);                                //递归调用孩子结点,从叶子结点开始dp
            dp[node][1] += dp[i][0];                   //上司来,下属不来
            dp[node][0] += max(dp[i][1], dp[i][0]);    //上司不来,下属来、不来
        }
    }
}

int main()
{
    ifstream in("C:\\Users\\zhengyi\\Desktop\\ConsoleApplication1\\input.txt");
    cin.rdbuf(in.rdbuf());
    int i;
    int f, c, root;
    while (cin>>n)
    {
        memset(dp, 0, sizeof(dp));
        memset(leader, 0, sizeof(leader));
        for (i = 1; i <= n; i++)
        {
            cin>>dp[i][1];
        }
        while (cin>>c>>f, c || f)
        {
            leader[c] = f;
            root = f;
        }
        while (leader[root])                       //查找父结点
            root = leader[root];
        tree_dp(root);
        int imax = max(dp[root][0], dp[root][1]);
        printf("%d\n", imax);
    }
    system("pause");
    return 0;
}

python code:

file=open('datahdu1520.txt','r')
line=file.readline()
N=int(line.strip('\n'))
activity=[int(file.readline().strip('\n')) for i in range(N)]
leader=[i for i in range(N)]
root=0
while True:
    line=file.readline()
    if line=="0 0":
        break
    line=line.split()
    leader[int(line[0])-1]=int(line[1])-1
    root=int(line[1])-1
dp=[[0 for col in range(2)] for row in range(N)]

def func(person):
    dp[person][0]=0
    dp[person][1]=activity[person]
    for i in range(N):
        if leader[i]==person and i!=person:
            func(i)
            dp[person][0]=dp[person][0]+max(dp[i])
            dp[person][1]=dp[person][1]+dp[i][0]

while leader[root]!=root:
    root=leader[root]
func(root)
print(max(dp[root]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值