第六届蓝桥杯省赛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;
}

 

posted @ 2020-09-22 14:34  funforever  阅读(247)  评论(0编辑  收藏  举报