树形dp--hdu 1520 anniversary party

题意:一个大学准备举办80周年校庆活动。该校的人事关系是一棵树形结构,父结点是上司,子结点是下属。每个结点都有一个值,限制条件是父子结点不能同时参加校庆活动(即如果父结点参加了那么他的孩子结点就不能参加,如果有一个孩子结点参加,那么父结点就不能参加)。最后求满足限制的情况下,值的和最大的值是多少。

f[N]:表示i结点的父结点;

rating[N]:一个结点的值

dp[i][0]:以i为根结点的子树所取的最大值(i结点没有被取到)

dp[i][1]:以i为根结点的子树所取的最大值(i结点被取到)

状态转移方程:

dp[root][0] += max(dp[children[root][i]][0], dp[children[root][i]][1]);
dp[root][1] += dp[children[root][i]][0];

最后的结果是包含根结点的最大值和不包含根结点的最大值中的一个。

#include<vector>
#include<cstdio>
using namespace std;

const int N = 6005;

int f[N];
int ratings[N];
vector<int> children[N];
int dp[N][2];

int max(int a, int b){
    return a > b ? a : b;
}

void dfs(int root){
    int len = children[root].size();
    dp[root][1] = ratings[root];
    for (int i = 0; i < len; ++i){
        dfs(children[root][i]);
    }
    for (int i = 0; i < len; ++i){
        dp[root][0] += max(dp[children[root][i]][0], dp[children[root][i]][1]);
        dp[root][1] += dp[children[root][i]][0];
    }
}

int main(){
    int n, a, b;
    while (scanf("%d", &n) != EOF){
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; ++i){
            scanf("%d", &ratings[i]);
            f[i] = -1;
        }
        while (scanf("%d%d", &a, &b)){
            if (a == 0 && b == 0) break;
            f[a] = b;
            children[b].push_back(a);
        }
        int root = 1;
        while (f[root] != -1) root = f[root];
        dfs(root);
        printf("%d\n", max(dp[root][0], dp[root][1]));
    }
    return 0;
}

 

posted @ 2015-08-19 20:17  marchlyp  阅读(194)  评论(0编辑  收藏  举报