HDU1520 Anniversary party 树形DP

题目链接:HDU1520
题目大意:给你n个点,每个点拥有相应的权值,要求选一部分点使得他们权值和最大,要求父亲节点和孩子节点不能同时被选中。
第一次见到树形DP
注释写的很详细
AC代码

/*
2017年7月31日11:39:59
HDU1520 
AC代码 
*/
#include<stdio.h>
const int maxn=6000+10;
//int a[maxn]; 
struct Tree{
    int father;//father 
    int child;//child 
    int brother;//brother 
    int absent,present;//缺席,出席 
    //求两种状态 权值更大的一种 
    int calc(){
        return absent > present ? absent : present;
    } 
    //初始化 present 的权值输入的时候会初始化 
    void init(){
        father = child = brother = absent = 0;
    }
}tree[maxn];

void dfs(int root){
    /*
    取当前节点的孩子节点
    如果没有孩子,则会退出这一层 
    */
    int child=tree[root].child;
    while(child){
        //一直搜到最底层-叶子节点; 
        dfs(child);
        /*
        当父亲节点去的时候,孩子节点一定不能去。      
        */ 
        tree[root].present+=tree[child].absent;
        /*
        父节点不去,加上孩子节点 去和不去 两种状态的最大值 
        */ 
        tree[root].absent+=tree[child].calc();   
         /*
        搜这个节点的兄弟节点 
        也就是其父亲节点下的所有孩子节点 
        */
        child=tree[child].brother;

    }
}
int main(){
    int n,l,k;
    while(~scanf("%d",&n)){
        /*
        这里wa了好几次,仔细读题,题目中给的点是从1-7 
        所以存数据的时候也要从1-7开始存,一开始 我写的是0-n-1
        一直wa低级错误!!!! 
        */
        for(int i=1;i<=n;i++){
            //对每个节点的present权值初始化 
            scanf("%d",&tree[i].present);
            //对该点的其他值进行初始化 
            tree[i].init();
         }  
         /*
         把l节点的父亲置为k,再把l节点的兄弟节点置为k节点的孩子节点。
         更新k节点的孩子节点,如果k节点还有孩子,
         那么下个孩子的兄弟节点就是l 节点
         应该说清楚了吧…… 
         */
         while(scanf("%d%d",&l,&k),l+k){
            tree[l].father=k;
            tree[l].brother=tree[k].child;
            tree[k].child=l;
         }
         for(int i=1;i<=n;i++){
            //只有根节点的父亲为 0 
             //寻找根节点 
            if(!tree[i].father){
                dfs(i);
                printf("%d\n",tree[i].calc());
                break;
             }
         }
    }

    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值