「 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); }
作者:Mystical-W
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可
来源:http://www.cnblogs.com/bljfy
说明:客官~~您如果觉得写得好的话,记得给我点赞哦。如果要转载的请在合适的地方注明出处。谢
谢您的合作。您要是有什么有疑问的地方可以在下面给我评论。也可以直接私信我哦
声明:本作品由Mystical-W采用知识共享署名-非商业性使用-禁止演绎 4.0 国
际许可协议进行许可