题意
有一群人参加聚会,每个人有个快乐值,但是假如这个人遇到他的直接上司,他就不开心了(废话),问所有人的快乐值之和最大是多少
思路
这是一道树形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;
}