【dp每一天】HDU - 1520 Anniversary party(树形dp入门)

本文介绍了一个树形动态规划问题的具体实现过程。问题要求在给定的一棵树上,选择部分节点使得被选择的节点权值之和最大,但不能同时选择父节点和子节点。文章给出了详细的代码实现,并通过递归深度优先搜索(DFS)更新每个节点的状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给自己立个flag吧,每天晚上回来想个dp。

hdu - 1520

题目大意:给你一棵树,树上的父节点和子结点不能同时选,问这棵树可以选的权值最大和。

树形dp,用子节点的值来更新父节点。

有dp[i][0] = sum(max(dp[j][0],dp[j][1])); i->j;

dp[i][1] = sum(dp[j][0]) + d[i]; i->j;

这个因为自己智障还re(!?),忘记清空edgenum这个值了,导致无限加边。晚上脑子也得清醒啊

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 6000+50,inf = 0x3f3f3f3f;
int n;
int d[maxn];
int dp[maxn][2];
struct node
{
    int to,next;
    node(){}
    node(int a,int b){to = a; next = b;}
}edge[maxn<<2];

int deg[maxn],h[maxn];
int edgenum;
void add(int f,int t)
{
    edge[edgenum] = node(t,h[f]);
    h[f] = edgenum ++;
}
void dfs(int u)
{
    int res = 0,res2 = 0;

    if(dp[u][0] != -inf) return;
    if(h[u] == -1)
    {
        dp[u][0] = 0;
        dp[u][1] = d[u];
        return;
    }
    for(int i = h[u]; ~i ; i = edge[i].next)
    {
        int v = edge[i].to;
        dfs(v);
        res += (max(dp[v][1],dp[v][0]));
        res2 += dp[v][0];
    }
    dp[u][0] = res;
    dp[u][1] = res2 + d[u];
    return;
}
int main()
{
    int a,b;
    while(~scanf("%d",&n))
    {
        edgenum = 0;
        int flag = 0;
        for(int i = 1; i <= n; i++) deg[i] = 0,h[i] = -1,dp[i][0] = dp[i][1] = -inf;

        for(int i = 1; i <= n ; i++)
            scanf("%d",&d[i]);
        while(scanf("%d%d",&a,&b) && a+b)
        {
            add(b,a);
            deg[a] ++;
        }
        int root = -1;
        for(int i = 1; i <= n; i++)
            if(deg[i] == 0) {root = i;break;}
        dfs(root);
        printf("%d\n",max(dp[root][0],dp[root][1]));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值