洛谷P1122 最大子树和 树形DP
洛谷P1122 最大子树和
一道类似树形DP 的题目
首先我们随意定根 ,假设我们定根为 1,
那么我们设dp[ i ] 表示 在这个整个以1为根的树中
以 i为根的子树 i 这个点强制取到 , 我们再从他的子树中
取出一部分出来,最大能够取到的和
我们可知 当 枚举到dp[ u ] 时 ,我们看他的儿子取不取
如果v是它的儿子 若dp[ v ] > 0 那么我们就取 ,
否则就不取,取了反而会减少
这样类似最长连续子序列一样就行了
然后类似树形DP 一样从根节点向根扩展就行了 ,
也就是dfs下去
然后用每个点的dp[ i ] 更新 mx就行了 因为这样其实已经包括了
树的各种形态了
这个是因为 不管你的树长得多么奇形怪状,他对应到以1 为根的树中
一定有一个最高点,而这个最高点 就是 根节点
1 #include <cstdio> 2 #include <cmath> 3 #include <cstdlib> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 #include <iomanip> 9 using namespace std ; 10 11 const int maxn = 16011,inf = 1e9 ; 12 struct node{ 13 int to,pre ; 14 }e[maxn*2]; 15 int n,mx,cnt ; 16 int a[maxn],dp[maxn],head[maxn] ; 17 18 inline int read() 19 { 20 char ch = getchar() ; 21 int x = 0 , f = 1 ; 22 while(ch<'0'||ch>'9') { if(ch=='-') f = -1 ; ch = getchar() ; } 23 while(ch>='0'&&ch<='9') { x = x*10 + ch-48 ; ch = getchar() ; } 24 return x * f ; 25 } 26 27 inline void add(int x,int y) 28 { 29 e[++cnt] = (node){ y,head[ x ] } ; 30 head[x] = cnt ; 31 } 32 33 inline void dfs(int u,int fa) 34 { 35 dp[ u ] = a[ u ] ; 36 int v ; 37 for(int i=head[ u ];i;i = e[ i ].pre) 38 { 39 v = e[ i ].to ; 40 if( v!=fa ) 41 { 42 dfs(v,u) ; 43 dp[ u ]+=max(dp[ v ],0) ; 44 } 45 } 46 } 47 48 int main() 49 { 50 n = read() ; 51 mx = -inf ; 52 for(int i=1;i<=n;i++) 53 a[ i ] = read() ; 54 int x,y ; 55 for(int i=1;i<n;i++) 56 { 57 x = read() ; y = read() ; 58 add(x,y) ; add(y,x) ; 59 } 60 61 dfs( 1,-1 ) ; 62 for(int i=1;i<=n;i++) if( dp[ i ] > mx ) mx = dp [ i ] ; 63 printf("%d\n",mx) ; 64 return 0 ; 65 } 66