问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
一道最基础的 树形动态规划,今天重温一下,顺便温习一下邻接表的构建过程。
状态转移方程为:dp[s][0]+=dp[u][1]; dp[s][1]+=max(dp[u][0],dp[u][1]);(u为s的子节点,0表示包含自己的以s为根节点的子树最大值,1表示不包含自己的以s为根节点的子树最大值)
ac代码如下:
#include<iostream> #include<cstring> using namespace std; struct edge{ int e,next; }e[300000]; int head[150000],val[150000]; int N,M=0; void add(int s,int e1){ e[++M].e=e1; e[M].next=head[s]; head[s]=M; } long dp[150000][2]; bool v[150000]; void dfs(int s){ dp[s][0]=val[s]; dp[s][1]=0; for(int i=head[s];i!=-1;i=e[i].next){ int u=e[i].e; if(v[u]==0){ v[u]=1; dfs(u); dp[s][0]+=dp[u][1]; dp[s][1]+=max(dp[u][0],dp[u][1]); v[u]=0; } } } int main(){ cin>>N; int s,e; memset(head,-1,sizeof(head)); for(int i=1;i<=N;i++) cin>>val[i]; for(int i=1;i<N;i++){ cin>>s>>e; add(s,e);add(e,s); } int ans=0; memset(dp,0,sizeof(dp)); memset(v,0,sizeof(v)); v[1]=1; dfs(1); v[1]=0; ans=max(dp[1][0],dp[1][1]); cout<<ans<<endl; return 0; }