洛谷P1122—最大子树和(树形DP)
做了好几个树形DP的题,这道题就简单多了
题意
有N多花,有N-1条边,每朵花有美丽指数(可能为负),可以通过修剪,使剩下的一株美丽指数和最大,求最大的美丽指数之和
输入输出
第一行N
第二行N个美丽指数
接下啦N-1行,花与花之间的边
思路
这道题需要建双向边,关系不明确。是自底向上的树形DP
状态转移数组 dp[i]为以i为根节点的子树的美丽指数之和
状态转移关系dp[u] = max(dp[u],dp[u] + dp[v])
如果子结点的美丽指数为负数,就不加上它的美丽指数
#include <iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAX_N = 20000; //最多结点数
int tot; //标记边的序号
int head[MAX_N << 1],nxt[MAX_N << 1],ver[MAX_N << 1],edge[MAX_N << 1]; //建树要用到的数组
int dp[MAX_N];
int r[MAX_N];
void addedge(int u,int v){ //根据邻接表建树的过程
ver[++tot] = v; //tot条边指向的点为v
nxt[tot] = head[u]; //nxt保存以u为始点的下一条边的序号
head[u] = tot; //head[u]保存以u为始点的边的序号
}
void dfs(int u,int fa){
dp[u] = r[u];
for(int i = head[u];i;i = nxt[i]){
int v = ver[i];
if(v == fa) continue;
dfs(v,u);
dp[u] = max(dp[u],dp[u] + dp[v]);
}
}
int main(){
int n;
cin >> n;
for(int i = 1;i <= n;i++)
cin >> r[i];
int u,v;
for(int i = 0;i < n - 1;i++){
cin >> u >> v;
addedge(u,v);
addedge(v,u);
}
dfs(1,0);
int ans = -1e8; //初始值要是一个很小的数
for(int i = 1;i <= n;i++){
ans = max(ans,dp[i]);
}
cout << ans;
return 0;
}