Anniversary party
题目链接:H - 树形DP例题 HDU - 1520
题意
在一个有根树上每个节点有一个权值,每相邻的父亲和孩子只能选择一个,问怎么选择总权值之和最大。
思路
树形dp的常规入门题:设dp[i][0]表示:当前这个点不选,dp[i][1]表示当前这个点选择的最优解。
转移方程:dp[cur][0]+=max(dp[son][1],dp[son][0]);//当前这个点不选,那他的孩子可选可不选,取
最大的。
dp[cur][1]+=dp[son][0]//当前这点选择,那他的孩子就不能选择。
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const int MAXN = (int)6e3+7;
const int INF = (int)0x3f3f3f3f;
int N;
int dp[MAXN][2];
int rating[MAXN];
int fa[MAXN];
vector<int> G[MAXN];
int dfs(int root,int OK){
int res = 0;
if (dp[root][OK] != -1) return dp[root][OK];
if (OK){
rep(i,0,G[root].size()-1) {
int v = G[root][i];
res += dfs(v,0);
}
}
else {
rep(i,0,G[root].size()-1) {
int v = G[root][i];
res += max(dfs(v,0),dfs(v,1)+rating[v]);
}
}
return dp[root][OK] = res;
}
int findfa(int x){
if (x == fa[x]) return x;
return fa[x] = findfa(fa[x]);
}
void init(){
rep(i,0,N) G[i].clear();
mmm(dp,-1);
rep(i,1,N) fa[i] = i;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
while (cin >> N){
rep(i,1,N) cin >> rating[i];
init();
rep(i,1,INF){
int x,y;
cin >> x >> y;
if (x==0&&y==0) break;
G[y].pb(x);
fa[x] = y;
}
rep(i,1,N-1){
if (fa[i] == i) G[0].pb(i);
}
cout << dfs(0,0) << endl;
}
}