1. 程式人生 > 其它 >P1122 最大子樹和

P1122 最大子樹和

題面

小明對數學飽有興趣,並且是個勤奮好學的學生,總是在課後留在教室向老師請教一些問題。一天他早晨騎車去上課,路上見到一個老伯正在修剪花花草草,頓時想到了一個有關修剪花卉的問題。於是當日課後,小明就向老師提出了這個問題:

一株奇怪的花卉,上面共連有 \(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;
}