动态规划: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 }