luogu1122最大子树和--树形DP

题目链接

https://www.luogu.org/problemnew/show/P1122

真 - 搜索剪枝题

分析

这题也很好想,枚举每个节点与它儿子节点之间连的枝是剪还是不剪就好了

$f[now] = \sum max(f[son],0)$

但这题有个需要注意的地方,就是你可能将一个节点与它父亲之间相连的枝条剪掉以获得最大答案,由于$f[now]$指在$now$为根的子树范围内的最大答案,所以$ans=max(ans,f[now])$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <iostream>
#include <queue>
#define ll long long
#define ri register int
using std::min;
using std::max;
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while(!isdigit(c=getchar()))ne=c=='-';
x=c-48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
x=ne?-x:x;return;
}
const int maxn=16005;
const int inf=0x7fffffff;
struct Edge{
int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=0;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
int a[maxn],f[maxn],n;
int ans=-inf;
void dfs(int now,int fa){
int v;
f[now]=a[now];
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa)continue;
dfs(v,now);
f[now]+=max(f[v],0);
}
ans=max(ans,f[now]);//也可能把它与父亲相连的枝剪掉
return ;
}
int main(){
int x,y;
read(n);
for(ri i=1;i<=n;i++)read(a[i]);
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
dfs(1,0);
printf("%d\n",ans);
return 0;
}