动态规划:P1122最大子树和 树形DP

最大子树和
 
题目:

 

 思路:

  题目的意思其实就是给你一棵树,树的每一个结点都有点权,寻找一个子树,使得点权和最大。我们显然可以用DFS来做,因为是一棵树,且可以看成无向图,所以我们构建邻接图,任选一点为根都可以遍历到所有的点,我们就任选一点开始DFS,这一点的权值和sum先初始化为u点的点权,因为DFS就是算以u点为根的子树的最大点权和,那么搜到u点,起码也要u点的点权,然后我们定义一个d为0,目的就是求出所有邻接点i,j,k...这些点为根的子树的最大点权和,d+=max(dfs(邻接点),0),为什么要加一个max函数呢,因为如果小于0就不要这条邻接的边,最后sum+=d,return sum,dfs的返回值应该是以u点为根算出子树的最优点权和。注意可以加一个ans,每次在算出sum后更新ans.,为了避免重复向上访问点,我们可以加一个vis[]数组表示标记遍历过的点,使每个点只遍历一次。

DFS代码:

 

 

 

完整AC代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn = 16005;
 5 const int finf = -0x7ffffff;
 6 int head[maxn], to[2 * maxn], nex[2 * maxn], index;
 7 int val[maxn];
 8 int n, a, b, ans = finf;
 9 bool vis[maxn];
10 void add(int a, int b)
11 {
12     index++;
13     to[index] = b;
14     nex[index] = head[a];
15     head[a] = index;
16 
17 }
18 int dfs(int u)
19 {
20     vis[u] = 1;
21     int d = 0;
22     int res = val[u];
23     for (int i = head[u]; i; i = nex[i])
24     {
25         int j = to[i];
26         if (vis[j])
27             continue;
28         d += max(0, dfs(j));
29     }
30     res += d;
31     ans = max(ans, res);
32     return res;
33 }
34 int main()
35 {
36     cin >> n;
37     for (int i = 1; i <= n; ++i)
38     {
39         cin >> val[i];
40     }
41     for (int i = 1; i < n; ++i)
42     {
43         cin >> a >> b;
44         add(a, b);
45         add(b, a);
46     }
47     dfs(1);
48     cout << ans;
49     return 0;
50 }

 

 

posted @ 2022-05-02 10:40  朱朱成  阅读(119)  评论(0编辑  收藏  举报