【Luogu】P1122最大子树和(DFS,树上DP)

题目链接

感觉自己DP好烂啊   道道看题解

钦定1为根,DFS搜索子树权值。如果子树权值大于0就将当前节点加上子树权值,反之就把子树扔掉。最后在所有节点的权值中寻找最优解。

void dfs(int x,int fa){
    if(f[x]>0)    return;
    f[x]+=que[x];
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        dfs(to,x);
        if(f[to]>0)    f[x]+=f[to];
    }
    if(ans<f[x])    ans=f[x];
}

这就是DFS。第一行是个记忆化,如果f[x]已经被计算过返回。但我写错了……

然后 f[x]+=que[x]。因为f[x]是节点x及x子树的权值,如果不加上自己怎么行。

接下来是一个遍历,寻找自己所有的儿子节点。如果计算得出f[to]>0,那么说明这个子节点需要留着,因此f[x]+=f[to]

最后ans在所有f[x]中取得最优解。

代码如下

#include<cstdio>
#include<cctype>
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    int next,to;
}edge[1000000];
int head[1000000],num;
inline void add(int from,int to){
    edge[++num]=(Edge){head[from],to};
    head[from]=num;
}

int que[1000000];
int f[1000000];
int ans=-0x7fffffff;
void dfs(int x,int fa){
    if(f[x]>0)    return;
    f[x]+=que[x];
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        dfs(to,x);
        if(f[to]>0)    f[x]+=f[to];
    }
    if(ans<f[x])    ans=f[x];
}

int main(){
    int n=read();
    for(int i=1;i<=n;++i)    que[i]=read();
    for(int i=1;i<n;++i){
        int from=read(),to=read();
        add(from,to);
        add(to,from);
    }
    dfs(1,1);
    printf("%d",ans);
    return 0;
}
    
原文地址:https://www.cnblogs.com/cellular-automaton/p/7497972.html