「 Luogu P1122 」 最大子树和

# 题目大意

真讨厌题面写的老长老长的。

这个题的意思就是给定一棵无根树,每个节点都有一个美丽值(可能是负数),可以删掉一些边来删除某些点,现在要求你求出可以删掉任意条边的情况下,这个树上的剩余节点的美丽值之和的最大值。

 

# 解题思路

以每一个节点为根,做 $\text{dfs}$,考虑到这样的一个性质,如果一棵子树节点的美丽值之和为负数,那就可以将这棵子树全部删掉。

所以就在 $\text{dfs}$ 的同时记录一下子树的美丽值之和。如果你这样做的话,会得到 $70$ 分的好成绩(会 $\text{TLE}$ 三个点)。所以要加入记忆化,应该没什么难的,这样子来看的话,这其实是一道树形 $\text{DP}$ 的入门级题目。不过懒得改了,就交记忆化的版本吧。

 

# 附上代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 16003;
int n, a[maxn], rt, head[maxn], cnt, ans, num[maxn];
struct edge {
    int nxt, u, v;
}ed[maxn << 1];
inline void addedge(int x, int y) {
    ed[++cnt].nxt = head[x];
    head[x] = cnt;
    ed[cnt].u = x, ed[cnt].v = y;
}
inline int dfs(int x, int fr) {
    if(num[x]) return num[x]>0?num[x]:0;
    num[x] = a[x];
    for(int i=head[x]; i; i=ed[i].nxt) {
        if(ed[i].v == fr) continue;
        num[x] += dfs(ed[i].v, x);
    }
    if(num[x] < 0) return 0;
    return num[x];
}
int main() {
    scanf("%d", &n);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    int x, y;
    for(int i=1; i<n; i++) {
        scanf("%d%d", &x, &y);
        addedge(x, y);
        addedge(y, x);
    }
    for(int i=1; i<=n; i++) {
        ans = max(ans, dfs(i, 0));
    }
    printf("%d", ans);
}

 

posted @ 2018-09-11 17:09  Mystical-W  阅读(170)  评论(0编辑  收藏  举报