树形DP:Anniversary party POJ - 2342

Description
There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests’ conviviality ratings.
Input
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go N – 1 lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0
Output
Output should contain the maximal sum of guests’ ratings.
Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
Sample Output
5
题目概要
第一行输入N表示人数。接下来的N行表示1~N的权重。接下来的N-1行每行输入K L,表示L是K的直属上司。要求不让上司和他的下属一起参加聚会并且要求权重达到最大。
问题分析
该问题是一个树形DP问题。
我们从每一个节点出发考虑这个问题,每一个人只有参加聚会或者不参加聚会这两种情况,只要取这两种情况下权重之和的最大值,几位最终结果。
假设已经实现函数int get_dp(int root,int i)i取0或1表示标号为root的职员有没有参加聚会,返回他参加聚会和不参加聚会的情况下的最大权重。注:root为当前子树内的最高级员工。所以我们只要求的最高级员工在与不在的权重并取最大值即为最终结果。
函数实现:
i==0,root没有参加聚会,则他的直属员工有可能参加或者有可能不参加,计算每一个孩子节点参加或者不参加聚会的权重,并取最大值,累计到dp[root][0]中。
i==1,root参加了聚会,则他的直属员工都没有参加聚会,计算每个孩子节点没有参加聚会的权重,累计到dp[root][1]中,并加上自身的权重。
代码实现

#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
int dp[6002][2];
vector< vector<int> > vec;
int w[6002];
int get_dp(int root,int i){
    if(dp[root][i]!=-1)return dp[root][i];
    if(vec[root].size()==1&&i==0){
        return 0;   
    }
    else if(vec[root].size()==1&&i==1){
        return 1;
    }
    if(i==0){
        int temp=0;
        for(int j=1;j<vec[root].size();j++)
            temp+=max(get_dp(vec[root][j],0),get_dp(vec[root][j],1));
        dp[root][i]=temp;
        return dp[root][i];
    }
    else if(i==1){
        dp[root][i]=w[root];
        for(int j=1;j<vec[root].size();j++)
            dp[root][i]+=get_dp(vec[root][j],0);
        return dp[root][i];
    }
}
int main(){
    int N;
    scanf("%d",&N);
        for(int i=1;i<N+1;i++){
            scanf("%d",&w[i]);
            vec.push_back(vector<int>(1,0));
            dp[i][0]=-1;
            dp[i][1]=-1;
        }
        vec.push_back(vector<int>(1,0));
        for(int i=1;i<N;i++){
            int L,K;
            scanf("%d %d",&L,&K);
            if(vec[L][0]==0)vec[L][0]=1;
            vec[K].push_back(L);
        }
        int k;
        for( k=1;k<N+1;k++)
            if(vec[k][0]==0)break;
        int result=max(get_dp(k,0),get_dp(k,1));
        printf("%d\n",result);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值