hdu1520 Anniversary party(树形dp基础题)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/readlnh/article/details/52226453

题意

有一群人参加聚会,每个人有个快乐值,但是假如这个人遇到他的直接上司,他就不开心了(废话),问所有人的快乐值之和最大是多少

思路

这是一道树形dp入门题,其实dp本身很简单,但是我对树形结构有一种莫名的恐惧。。。dp数组dp[i][0]表示i不放,dp[i][1]表示i放的情况下能达到的最大值,那么dp[u][0] += max(dp[v][0],dp[v][1]),这里当u不放时,那么他的下属放不放均可,而dp[u][1] += dp[v][0],当u放的情况下,他的下属是不能参加party的。这里dp式实际是非常简单的,关键是这个dp在树上,我用vector像存图一样存了这颗树(这显然是一颗树),然后用递归的方式来遍历这颗树(递归从树的根节点开始,一层层往下,一直到叶子节点)

代码

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <vector>
using namespace std;

const int kMaxn = 6000 + 10;

int dp[kMaxn][2];
int val[kMaxn];
bool vis[kMaxn];
vector<int>g[kMaxn];

void dfs(int u) {
    int len = g[u].size();
    //vis[u] = true;
    dp[u][0] = 0;
    dp[u][1] = val[u];
    for(int i = 0; i < len; i++) {
        int v = g[u][i];
        //if(vis[v]) continue; 网上的代码都有这句,实际上这是一颗树根本不会重复访问同一个节点,所以没有这个也无所谓
        dfs(v);
        dp[u][0] += max(dp[v][1], dp[v][0]);
        dp[u][1] += dp[v][0];
    }
}

int main() {
    int n;
    while(~scanf("%d", &n)) {
        for(int i = 1; i <= n; i++)  {
            scanf("%d", &val[i]);
            g[i].clear();
        }
        int u,v;
        memset(vis, false, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        while(scanf("%d %d", &u, &v), u||v) {
            g[v].push_back(u);
            vis[u] = true;
        }
        for(int i = 1; i <= n; i++)
            if(!vis[i]) {
                memset(vis, false, sizeof(vis));
                dfs(i);
                printf("%d\n", max(dp[i][0], dp[i][1]));
                break;
            }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/readlnh/article/details/52226453