【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; }