poj 2324 Anniversary party(树形DP)

时间:2024-01-01 12:09:39
/*poj 2324 Anniversary party(树形DP)
---用dp[i][1]表示以i为根的子树节点i要去的最大欢乐值,用dp[i][0]表示以i为根节点的子树i不去时的最大欢乐值,
---于是当i去时,i的所有儿子都不能去:dp[i][1]=sum(dp[j][0])+a[i],其中j是i的儿子节点。
---当i不去时,i的儿子可去也可不去:dp[i][0]=sum(max(dp[j][0],dp[j][1])),j是i的儿子节点
---边界条件:当i时叶子节点时,dp[i][1]=a[i],dp[i][0]=0;
*/
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 6000 + 5; int a[maxn], dp[maxn][2];
vector<int>vec[maxn]; //记忆化搜索
int dfs(int u, int k){
if (dp[u][k] >= 0)return dp[u][k];
int n = vec[u].size();
if (k == 0)dp[u][k] = 0;
else dp[u][k] = a[u];
for (int i = 0; i < n; i++){
int v = vec[u][i];
if (k == 0) dp[u][0]+=max(dfs(v, 1), dfs(v, 0));
else dp[u][1] += dfs(v, 0);
}
return dp[u][k];
}
int main(){
int n,i,u,v;
while (scanf("%d%d", &n, &a[1])&&n){
for (i = 0; i <= n; i++) vec[i].clear(); for (i = 2; i <= n; i++)scanf("%d", &a[i]); for (i = 1; i < n; i++){
scanf("%d%d", &u, &v);
vec[v].push_back(u);
}
memset(dp, -1, sizeof(dp));
int ans = -1;
for (i = 1; i <= n; i++)
ans = max(ans, max(dfs(i, 0), dfs(i, 1)));
printf("%d\n", ans);
}
}