洛谷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;
}

posted @ 2021-07-16 22:00  inss!w!  阅读(62)  评论(0编辑  收藏  举报