P1122 最大子树和【树形dp】
没有思路没关系,先自己搞一组数据
(随便搞的)
18
-9 -1 -3 -3 2 -8 -3 2 -1 3 3 4 -6 1 2 -1 -9 2
1 2
1 3
2 4
2 5
2 6
3 7
4 8
5 9
5 10
6 11
7 12
7 13
8 14
8 15
11 16
11 17
13 18
(节点编号按bfs序)
从根节点递归
f [ i ] 记录从树梢到i节点的最大美丽值,即
f [ i ] 等于所有所有子树的最大美丽值+自己的美丽值
魅力值是负的节点当然我们不想选了啊
所以如果 f [ i ]是负值,我们就可以直接把他连同子树减掉,也就是赋成0
如上图红色值为每个节点的 f [ i ] = 自己的美丽值 + 所有子节点的红色值
灰色值是负值,减掉后变成 0
最后找到每个节点的红色值 f [ i ]的最大值即为答案
附AC code:
#include<bits/stdc++.h>
using namespace std;
const int N=16010;
int n,m,x,y,f[N],ver[2*N],head[N],tot,ans,next[2*N],w[N];
void add(int x,int y)//加边
{
ver[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
void dp(int x,int y)
{
for(int i=head[x];i;i=next[i])
{
if(ver[i]==y) continue;//防止重复找边
dp(ver[i],x);
f[x]+=f[ver[i]];
}
f[x]=max(f[x]+w[x],0);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dp(1,0);
for(int i=1;i<=n;i++) ans=max(ans,f[i]);
printf("%d",ans);
return 0;
}