洛谷P1122 最大子树和

题面:

解题:

  • 树形数据结构

不妨用一个类 Tree 来储存每个节点的数据,其中除了它上面和下面与之相连接的节点,我还引入了两个变量:m_Num和f,分别用于储存其节点的自身值、从上往下加到该枝头的最大子树和……

  • DFS(深度优先搜索)

引用高赞题解区大佬神云_cloud的图来解释说明:

下图中,1/2/3号节点均只连接一端,则可以将其视为“叶子”或“顶端”,

定义严格的搜索顺序是从上往下,则其f值(最大子树和)就是它本身,f[1]=f[2]=f[3]=-1;

对于1/2/3号节点下方的4/5/6号节点,其f值除了加上自身外,还要考虑要不要加上其上方节点的值,

f[4]=max(m_Num[4]+f[1])=1,f[1]是负数所以把1-4的枝条剪断,同理可求f[5]=f[6]=1;

对于7号节点,我们可将其视为树根,递归将在这里结束,观察到其上方有4/5/6三个节点,

连接4/5/6号节点都要判断是否剪断,因此,创建临时变量tempSum:

int tempSum=0;  
tempSum=max(tempSum , tempSum+f[4]);//判断4-7是否要剪断,若不剪断,tempSum+f[4]
tempSum=max(tempSum , tempSum+f[5]);//判断5-7是否要剪断,若不剪断,tempSum+f[5]
tempSum=max(tempSum , tempSum+f[6]);//判断6-7是否要剪断,若不剪断,tempSum+f[6]
f[7]=max(f[7],m_Num[7]+tempSum);

构建数据过程结束,接下来只要简单地遍历所有节点,找出最大的f值即答案

AC代码奉上

#include<iostream>
#include<algorithm>
#include<vector>
#define MAXN int(2e6+5)

using namespace std;

class Tree //树形数据结构,用类来管理
{
public:
    vector<int>a_T; //aboveTree  上端树
    vector<int>b_T; //behindTree 下端树
    int m_Num = 0;  //节点自身值
    int f = 0;      //加到该枝时的最大和
    Tree(int num)
    {
        this->m_Num = num; //构造函数初始化节点自身值
        this->f = num;     //加到自身时,必须要算上自己的节点值
        this->a_T.push_back(0);//占掉0位,从1开始
        this->b_T.push_back(0);//占掉0位,从1开始
    }
};

int n, root, a[MAXN] = { 0 };
vector<Tree>v;//存放树节点的容器

void dfs(int id, int pre) //从一个顶端,搜索到底端 注:pre参数只判断是不是顶端,没用……
{
    if (pre != 0)
    {
        int tempSum = 0;
        for (int i = 1; i <= v[id].a_T.size() - 1; i++)
        {
            tempSum = max(tempSum, tempSum + v[v[id].a_T[i]].f);
        }
        v[id].f = max(v[id].m_Num + tempSum, v[id].f);
    }
    
    for (int i = 1; i <= v[id].b_T.size() - 1; i++)
        dfs(v[id].b_T[i], id);

    if (v[id].b_T.size() == 1) { root = id; return; }
}

int main()
{
    v.push_back(Tree(0));
    cin >> n;
    for (int i = 1; i <= n; i++) 
    {
        cin >> a[i];
        Tree t(a[i]);
        v.push_back(t); //初始化n个树节点
    }

    for (int i = 1; i <= n - 1; i++)
    {
        int p, q; //需要连接的枝条两端
        cin >> p >> q;
        v[p].b_T.push_back(q);  //连接,p、q谁上谁下无所谓
        v[q].a_T.push_back(p);
    }

    for (int i = 1; i <= v.size() - 1; i++)
        if (v[i].a_T.size() == 1)dfs(i, 0);//从顶部(a_T.size==1)开始,向下搜索

    int ans = -1e7+5;  //答案初始化为负无穷
    for (int i = 1; i <= v.size() - 1; i++)
        ans = max(ans, v[i].f);  //比较各个节点的f值,找出最大的f值

    cout << ans << endl;  //输出这个最大值
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值