首页 > 代码库 > POJ2342Anniversary party(树形dp)

POJ2342Anniversary party(树形dp)

POJ2342Anniversary party(树形dp)

题目连接

题目大意:有一个聚会,现在需要邀请人来参加这个聚会来增加活跃度,但是这N个人中,除了一个人以外,其余的人都有直接的上司,如果他们碰到他们的直接的上司的话,那么他们就会很不愉快。现在要求你让所有的人都愉快的情况下,使得聚会的活跃度,达到最大。

解题思路:之前没有接触过树形dp,看了题解大概明白。题型大概就是N个节点形成了一棵树,根节点需要用到子节点的数据。思路:先把每个点的直接的子节点找出来,存在vector里面。然后找出根节点,最后再dfs从根找到子节点,然后数据再一层一层的返回。
dp[i][0] 代表i这个节点不选 dp[i][1] 代表i这个节点选择了
dp[i][0] += max (dp[子节点][0], dp[子节点][1]);//上层节点不选了,那么子节点可选可不选
dp[i][1] += max(dp[子节点][0] + score[i], dp[i][1]); //上层节点选了,那么子节点都是不可选的

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cstdlib>

using namespace std;

const int maxn = 6005;

int dp[maxn][2], vis[maxn];
int score[maxn];

vector<int> node[maxn];
int f[maxn];

void tree_dp (int num) {
    vis[num] = 1;
    dp[num][0] = 0;
    dp[num][1] = score[num];
    //printf ("%d %d\n", num, node[num].size());
    for (int i = 0; i < node[num].size(); i++) {

        int u = node[num][i];
        if (vis[u])
            continue;
        tree_dp(u);
        dp[num][0] += max(dp[u][1], dp[u][0]);
        dp[num][1] += dp[u][0];
    }
}

void init () {
    for (int i = 0; i < n; i++) 
        scanf ("%d", &score[i]);

    for (int i = 0; i < n; i++)
        node[i].clear();
    memset (vis, 0, sizeof (vis));
    memset (f, -1, sizeof(f));
    while (scanf ("%d%d", &a, &b) && (a||b) ){
        node[b - 1].push_back(a - 1);
        f[a - 1] = b - 1;
    }
}

int main () {

    int n, a, b;
    while (scanf ("%d", &n) != EOF) {

        init();
        for (int i = 0; i < n; i++){
            if (f[i] == -1) { 
                tree_dp(i);
                printf ("%d\n", max(dp[i][0], dp[i][1]));
                break;
            }
        }
    }
    return 0;
}

POJ2342Anniversary party(树形dp)