题目大意
给定一颗树,每个结点有一个分值,父亲结点和子结点不能同时选,问你最多能获得的分值是多少?
题解
第一次独立做出树形DP来(虽然很水),撒花庆祝一下,哈哈~~~话说树形DP和记忆化好相似的说~~~(似乎没区别?)。用dp[root][0]表示以root为根的子树不选root能够获得的最大值,dp[root][0]=max(dp[son(root)][1],dp[son(root)][0]),同理dp[root][1]表示以root为根的子树选择root能够获得的最大值,只需把root的所有子节点形成的子树并且不选子节点能够获得的最大值全部加起来就是dp[root][1],即dp[root][1]=num[root]+dp[son(root)][0].
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #define MAXN 6005 int dp[MAXN][2],num[MAXN]; vector<int>ivec[MAXN]; bool visit[MAXN]; int dfs(int root,int state) { if(dp[root][state]) return dp[root][state]; if(ivec[root].empty()) { if(state) return dp[root][state]=num[root]; else return dp[root][state]=0; } if(state) { dp[root][state]=num[root]; for(size_t i=0; i<ivec[root].size(); i++) dp[root][state]+=dfs(ivec[root][i],0); } else { for(size_t i=0; i<ivec[root].size(); i++) dp[root][state]+=max(dfs(ivec[root][i],0),dfs(ivec[root][i],1)); } return dp[root][state]; } int main() { int n; while(scanf("%d",&n)!=EOF) { for(int i=1; i<=n; i++) { scanf("%d",&num[i]); ivec[i].clear(); } memset(visit,false,sizeof(visit)); int a,b; while(scanf("%d%d",&a,&b),a+b) { ivec[b].push_back(a); visit[a]=true; } int root; for(int i=1; i<=n; i++) if(!visit[i]) { root=i; break; } memset(dp,0,sizeof(dp)); printf("%d ",max(dfs(root,0),dfs(root,1))); } return 0; }