蓝桥-算法训练 ALGO-4 结点选择【树形DP】

题目链接

题目描述:

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
n <= 100000,权值均为不超过1000的正整数。


题解:

因为一个点有被选择和不被选择两个状态,所以设计状态 dp[x][z] 表示以点 x 为子树且点 x 在 z 状态下的最大值,z = 0表示不选点 x,z = 1表示选择点 x,状态转移方程为:
d p [ x ] [ 0 ] = ∑ y ( x , y ) ∈ E , y ≠ p a r e n t [ x ] m a x ( d p [ y ] [ 1 ] , d p [ y ] [ 0 ] ) d p [ x ] [ 1 ] = w [ x ] + ∑ y ( x , y ) ∈ E , y ≠ p a r e n t [ x ] d p [ y ] [ 0 ] dp[x][0] = \sum_y^{(x,y)∈E,y≠parent[x]}{max(dp[y][1],dp[y][0])}\\ dp[x][1] = w[x]+\sum_y^{(x,y)∈E,y≠parent[x]}{dp[y][0]} dp[x][0]=y(x,y)Ey=parent[x]max(dp[y][1]dp[y][0])dp[x][1]=w[x]+y(x,y)Ey=parent[x]dp[y][0]
我们以 1 为树的根进行dfs,最终 max(dp[1][0], dp[1][1]) 即为解。
注意:当图为双向边且使用链式前向星时,数组别忘了开两倍!


AC Codes:

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 1e5 + 6, M = 1e9 + 7;

int head[N], Next[N << 1], ver[N << 1], parent[N], tot;
int w[N], dp[N][2];

void add(int u, int v) {
    ver[++tot] = v;
    Next[tot] = head[u], head[u] = tot;
}

void dfs(int x) {
    dp[x][1] = w[x];
    for (int i = head[x]; i; i = Next[i]) {
        int y = ver[i];
        if (y == parent[x]) continue;
        parent[y] = x;
        dfs(y);
        dp[x][1] += dp[y][0], dp[x][0] += max(dp[y][0], dp[y][1]);
    }
}

int main() {
    //freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    tot = 1;
    for (int i = 1; i <= n; i++) cin >> w[i];
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        add(x, y), add(y, x);
    }
    parent[1] = 0;
    dfs(1);
    cout << max(dp[1][0], dp[1][1]) << '\n';
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值