P1122 最大子樹和
阿新 • • 發佈:2022-03-04
題面
小明對數學飽有興趣,並且是個勤奮好學的學生,總是在課後留在教室向老師請教一些問題。一天他早晨騎車去上課,路上見到一個老伯正在修剪花花草草,頓時想到了一個有關修剪花卉的問題。於是當日課後,小明就向老師提出了這個問題:
一株奇怪的花卉,上面共連有 \(N\) 朵花,共有 \(N-1\) 條枝幹將花兒連在一起,並且未修剪時每朵花都不是孤立的。每朵花都有一個“美麗指數”,該數越大說明這朵花越漂亮,也有“美麗指數”為負數的,說明這朵花看著都讓人噁心。所謂“修剪”,意為:去掉其中的一條枝條,這樣一株花就成了兩株,扔掉其中一株。經過一系列“修剪“之後,還剩下最後一株花(也可能是一朵)。老師的任務就是:通過一系列“修剪”(也可以什麼“修剪”都不進行),使剩下的那株(那朵)花卉上所有花朵的“美麗指數”之和最大。
老師想了一會兒,給出了正解。小明見問題被輕易攻破,相當不爽,於是又拿來問你。
思路
本題可以歸納為求樹上最大子樹和問題。
可以用樹形DP做。
如果當前節點為 \(u\),那麼以 \(u\) 為根的最大子樹和為:(\(v\) 是當前列舉到的 \(u\) 的子節點)
\(f[u]=f[u]+a[u]+\max\{f[v],0\} \text{ (v is the sub node of u)}\)
然後建圖的鄰接矩陣(樹?)跑圖遍歷就好了。
程式碼
#include <bits/stdc++.h> using namespace std; int n; int a[20005],ans=INT_MIN; vector<int> G[20005]; // Matrix int f[20005]; void add(int u,int v){ G[u].push_back(v); } void add_undirected(int u,int v){ add(u,v);add(v,u); } void dp(int u,int parent){ f[u]=a[u]; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(v==parent){ continue; } dp(v,u); if(f[v]>=1){ f[u]=f[u]+f[v]; } } } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1,u,v;i<n;i++){ cin>>u>>v; add_undirected(u,v); } dp(1,0); for(int i=1;i<=n;i++){ ans=max(ans,f[i]); } cout<<ans<<endl; return 0; }