题意:在一棵树上选出一些点,每个点都有一个权值,使得和最大,前提是,父节点和子节点只能选一个。
分析:整个代码与1054基本一样的,就是状态转移方程变了 ,因为题目加了一些限制
dp[i][0]表示以i为根节点的不选i树的最大权值和
dp[i][1]表示以i为根节点的选i的树的最大权值和
状态转移方程:
dp[i][0]+=max(dp[son[i][j]][0],dp[son[i][j]][1]),(0<j<size[i])
dp[i][1]+=dp[son[i][j]][0];(0<j<size[i]) size[i]表示i节点的儿子数
#include<iostream> #include<algorithm> #include<vector> using namespace std; int v[6001],n,f[6001]; vector<int> son[6001]; int dp[6001][2]; int dfs(int pos,int val) { if(dp[pos][val]!=INT_MIN) return dp[pos][val]; int sum; if(val==1) sum=v[pos]; else sum=0; int size=son[pos].size(); for(int i=0;i<size;i++) { if(val==1) sum+=dfs(son[pos][i],0); else sum+=max(dfs(son[pos][i],0),dfs(son[pos][i],1)); } return dp[pos][val]=sum; } int main() { while(scanf("%d",&n)==1) { for(int i=1;i<=n;i++) { scanf("%d",&v[i]); son[i].clear(); f[i]=i; dp[i][0]=dp[i][1]=INT_MIN; } int a,b; while(scanf("%d %d",&a,&b)) { if(a==0 && b==0) break; son[b].push_back(a); f[a]=b; } int ans; for(int i=1;i<=n;i++) { if(f[i]==i) { ans=max(dfs(i,0),dfs(i,1)); break; } } printf("%d\n",ans); } return 0; }