题意,给定一颗有根树,每个节点有一个权值,如果取父亲节点的权值,那么所有儿子节点的权值不能取。试规划一种节点选取方案,使得取到的节点权值和最大,只要求给出最大值。
容易想到:父亲选了。儿子一定不能选。父亲没选,儿子可以选,也可以不选。(因为有负权值)
用dp[x][1]表示选了x节点后,x和其所有子孙的合规选法的最大权值和。
用dp[x][0]表示没选x节点,其所有子孙的合规选法的答案权值和。
dp[x][1]=(dp[x的儿子][0])+自己的权值;
dp[x][0]=(max(dp[x的儿子][1],dp[x的儿子][0]));
状态的定义一定要明确好。不然父亲,儿子,孙子,容易搞晕的。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n;
int dp[6007][7],a[6007],vis[6007];
vector<int>g[6007];
int dfs(int x){
vis[x]=1;
dp[x][1]=a[x];
int val=0;
rep(i,0,g[x].size()-1){
int v=g[x][i];
if(vis[v]==1)continue;
dfs(v);
dp[x][1]+=dp[v][0];
dp[x][0]+=max(dp[v][0],dp[v][1]);
}
}
int main(){
cin>>n;
rep(i,1,n)cin>>a[i];
rep(i,1,n-1){
int x,y;
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
vis[x]=1;
}
int root;
rep(i,1,n)if(vis[i]==0)root=i;
memset(vis,0,sizeof(vis));
dfs(root);
cout<<max(dp[root][1],dp[root][0]);
//cout<<endl<<dp[3][0];
return 0;
}