第六届蓝桥杯省赛C++B组 生命之树
通过理解题意注意是要任意两点要有连线,不一定是直接相连,说白了就是求哪个连通块权值大。很简单的树形dp计算,但是要注意是从叶节点往上,来求出结果,如果从顶到底,只能计算出以第一个搜索为根的最小,但是答案不一定包括你第一个搜索的根,所以只能采用从下到上的方法,这样把所有子节点的值均为正值的加起来,再加上自己的值即可。最后遍历所有节点,求得如果取某节点为根(根也要在S里面),则最大值是多少,由于答案必要有一个节点,所以遍历所有根即可得到答案,如果不遍历则若所有节点权值均为负数,答案本应该是最小的负数,但实际上会输出根的权值。
AC代码:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll INF = 0x3f3f3f3f3f3f3f3f; vector<int> vec[100005]; ll dp[100005]; int score[100005]; ll ans = -INF; int DP(int now, int fa) { dp[now] = score[now]; for(int i = 0; i < vec[now].size(); i++) { if(vec[now][i] == fa) continue; DP(vec[now][i], now); dp[now] += max(0ll, dp[vec[now][i]]); } } int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &score[i]); int u, v; for(int i = 0; i < n - 1; i++) { scanf("%d %d", &u, &v); vec[v].push_back(u); vec[u].push_back(v); } DP(1, 0); for(int i = 1; i <= n; i++) ans = max(ans, dp[i]); printf("%lld\n", ans); return 0; }