HDU 1520 浅谈简单树形动态规划

5 篇文章 0 订阅
博客探讨了一道关于树形动态规划的题目,描述了如何处理树状结构的问题,特别是如何设计状态并进行状态转移。作者通过实例解释了如何在树上寻找最大值,并提供了相应的代码实现。
摘要由CSDN通过智能技术生成

这里写图片描述
世界真的很大
趁着早上还没开始考试,悄咪咪地做一道树形DP
input里面没读出是多组数据,WA了两发才发现orz
主要是感觉还是不是很熟悉,特别是对于树形这一方面地问题
趁着NOIP之前赶紧地复习一下
就从这道水题开始吧

看题先:

description:

题目给出一棵树,每个节点都有其权值。如果选择了一个节点则不可以选择其父节点,问能取得的最大值

input:

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0

output:

Output should contain the maximal sum of guests’ ratings.

题目读起来就像是DP,考虑是在树上的问题,所以考虑树形DP
那么考虑树形DP的状态设计,一般与子树有关,即求出子树的答案然后合并上去
考虑在合并的时候,会影响答案合并的状态,就是子树的根节点选或者不选了,选了的话当前节点就不能选,两者的答案不一样当然要分开统计
于是得出状态设计 : f(i,0/1)
表示第i个子树内,i这个点选或者不选的最大值
f(i,0) = sigma max(f(v,0),f(v,1)) + ai,这是由于只要根不选,子树选不选都可以的缘故
f(i,1) = sigma f(v,0) ,这是由于根选了,所有子树的根都不能选的缘故
然后就OK了

完整代码:

#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;

struct edge
{
    int v,last;
}ed[100010];

int n,num=0,S;
int a[100010],head[100010],f[100010][2],in[100010];

void init()
{
    num=0;
    memset(head,0,sizeof(head));
    memset(in,0,sizeof(in));
    memset(f,0,sizeof(f));
}

void add(int u,int v)
{
    num++;
    ed[num].v=v;
    ed[num].last=head[u];
    head[u]=num;
}

void dfs(int u,int fa)
{
    f[u][1]=a[u];
    for(int i=head[u];i;i=ed[i].last)
    {
        int v=ed[i].v;
        if(v==fa) continue ;
        dfs(v,u);
        f[u][0]+=max(f[v][1],f[v][0]);
        f[u][1]+=f[v][0];
    }
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<n;i++)
        {   
            int u,v;
            scanf("%d%d",&u,&v);
            add(v,u),add(u,v);
            in[u]++;
        }
        scanf("\n0 0");
        for(int i=1;i<=n;i++)
            if(!in[i])
            {
                S=i;
                break ;
            }
        dfs(S,S);
        printf("%d\n",max(f[S][1],f[S][0]));
    }
    return 0;
}

嗯,就是这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值