P1122 最大子树和

解题思路

这道题目可以转化为在树上寻找一个连通子图,使得该子图中所有节点的美丽指数之和最大。由于题目允许通过修剪枝条(即删除边)来得到不同的子树,我们需要找到所有可能的子树中美丽指数和最大的那个。

关键点

  1. 树形DP:使用深度优先搜索(DFS)遍历树,计算以每个节点为根的子树的最大美丽指数和。

  2. 状态转移:对于每个节点,其最大美丽指数和可以是自身值,或者自身值加上所有子节点的最大美丽指数和(如果子节点的贡献为正)。

  3. 全局最大值:在计算完所有节点的最大美丽指数和后,取其中的最大值作为最终结果。

注意事项

  • 树的存储使用邻接表。

  • 需要避免重复访问父节点,防止形成环路。

  • 初始化时,每个节点的最大美丽指数和为其自身的值。

代码注释

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10; // 定义最大节点数,比题目要求的16000大一些

vector<int> g[N]; // 邻接表,存储树的边关系
int n,m; // n表示花的数量,m未使用可以删除
int a[N]; // 存储每朵花的美丽指数
int f[N]; // 存储每个节点的父节点,实际未使用可以删除
int w[N],v[N],dp[N]; // w和v未使用可以删除;dp[x]表示以x为根的子树的最大美丽指数和

// DFS遍历树,计算以x为根的子树的最大美丽指数和
void dfs(int x,int fa)
{
    f[x] = fa; // 记录父节点,实际未使用可以删除
    dp[x] = a[x]; // 初始化dp[x]为当前节点的美丽指数
    for(int i = 0; i < g[x].size(); i++) // 遍历所有子节点
    {
        int y = g[x][i]; // 子节点y
        if(y == fa) continue; // 避免回溯到父节点
        dfs(y,x); // 递归处理子节点
        // 状态转移:如果子节点的贡献为正,则加上子节点的dp值
        dp[x] = max(dp[x], dp[x] + dp[y]);
    }
}

int main()
{
    cin >> n; // 输入花的数量
    for(int i = 1; i <= n; i++) cin >> a[i]; // 输入每朵花的美丽指数
    for(int i = 1; i < n; i++) // 输入n-1条边
    {
        int x,y; cin >> x >> y;
        g[x].push_back(y); // 无向图,双向加边
        g[y].push_back(x);
    }
    dfs(1,0); // 从根节点1开始DFS遍历,初始父节点为0
    int ans = -1e9; // 初始化答案为负无穷
    for(int i = 1; i <= n; i++) ans = max(ans,dp[i]); // 遍历所有节点,找到最大的dp值
    cout << ans; // 输出结果
    return 0;
}

 

posted @ 2025-06-11 20:22  CRt0729  阅读(16)  评论(0)    收藏  举报