ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树形dp/树的遍历

2022-03-09 01:00:52  阅读:204  来源: 互联网

标签:遍历 idx int ll dfs 树形 权值 include dp


牛客小白月赛45 E筑巢

题目链接:
https://ac.nowcoder.com/acm/contest/11222/E
题意概述:
给一棵n个节点的树,有边权和点权,权值可能为负,要求在树中取一个连通块,使该连通块的权值最大。
解析:
树形dp模板题。用f[i]表示以i为根的子树的权值最大值,可以选择一个连通块意味着在状态转移时,如果i的孩子f[j]为负,则可以不选这个孩子,或者将这个孩子的权值看作是0.
dfs过程:

  • 首先将i点的权值设置为f[i]的答案,然后遍历所有的孩子,dfs出孩子的权值f[j],f[i] += max(0, f[j]);
  • 注意是一棵树的遍历,所以dfs的时候传参是传u和fa,遍历孩子的时候,如果孩子==father,就continue.
    Ac代码
点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
typedef long long ll;
 
const int N = 1e5 + 10;
const int M = 2 * N;
 
int n;
ll h[N], e[M], ne[M], w[M], idx;
ll f[N], val[N];
 
void add(ll a, ll b, ll c){
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a]= idx ++;
}
 
void dfs(ll u, ll fa){
    f[u] = val[u];
    for(int i = h[u]; i != -1; i = ne[i]){
        ll j = e[i];
        if(j == fa) continue;
        dfs(j, u);
        f[u] += max(0ll, f[j] + w[i]);
    }
}
 
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%lld", &val[i]);
 
    memset(h, -1, sizeof h);
    for(int i = 1; i < n; i ++){
        ll x, y, z;
        scanf("%lld%lld%lld", &x, &y, &z);
        add(x, y, z), add(y, x, z);
    }
 
    dfs(1, -1);
 
    ll ans = -1e18;
    for(int i = 1; i <= n; i ++) ans = max(ans, f[i]);
 
    printf("%lld\n", ans);
 
    return 0;
}

Acwing 285. 没有上司的舞会

题目链接:
https://www.acwing.com/problem/content/287/
解析
好题。非常典型的树形dp。

  • 关于dp的具体过程

  • 关于树的遍历的一些思考

Ac代码

点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 6010;

int h[N], e[N], ne[N], idx;
int a[N], f[N][2], fa[N];
int n;

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void dfs(int u)
{
    f[u][1] = a[u];
    for(int i = h[u]; i != -1; i = ne[i]){
        int j = e[i];
        dfs(j);
        f[u][0] += max(f[j][1], f[j][0]);
        f[u][1] += f[j][0];
    }
    return;
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    memset(h, -1, sizeof h);
    for(int i = 1; i < n; i ++){
        int a, b;
        scanf("%d%d", &a, &b);
        add(b, a);
        fa[a] = b;
    }
    int root = 0;
    for(int i = 1; i <= n; i ++)
        if(fa[i] == 0) {
            root = i;
            break;
        }
    
    dfs(root);
    
    printf("%d\n", max(f[root][1], f[root][0]));
    
    return 0;
}

标签:遍历,idx,int,ll,dfs,树形,权值,include,dp
来源: https://www.cnblogs.com/bxhbxh/p/15983314.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有