首页 > 代码库 > 洛谷P1122 最大子树和 树形DP

洛谷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  

 

洛谷P1122 最大子树和 树形DP