Hdu 1520 Anniversary party (DP_树形DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520


题目大意:给定一棵关系树,每个节点有个权值,子节点和父节点不能同时选,问最后能选的最大价值是多少?


解题思路:树形DP入门题。由于子节点与父节点不能同时选,有人可能会用贪心思想,二者选其一肯定最优。其实不然,有可能父节点和子节点都不选,而要选子孙节点。不过只要再往深点想下,就可以得出动态规划的解法。每个节点要么选要么不选,和大多数选不选动归一样,来个dp[i][2],0表示不选,1表示不选,那我们只要从叶子节点往根结点不断更新dp[i][0]和dp[i][1]就可以了。

    状态转移方程:dp[i[[1] = sum(dp[j][0])                      (当前选了,子节点必定不能选,最优的情况是都不选,然后累加)

                          dp[i][0] = sum(max(dp[i][0],dp[i][1]))   (当选不选,子节点可选可不选,找大的那个状态)


测试数据:

1
1
0 0

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0


代码:

#include <stdio.h>
#include <string.h>
#define MAX 20000
#define max(a,b) (a)>(b)?(a):(b)


struct node {

    int v;
    node *next;
}*head[MAX],tree[MAX];
int n,ptr,dp[MAX][2];
int vis[MAX],num[MAX];


void Initial() {

    ptr = 1;
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));
    memset(head,NULL,sizeof(head));
}
void AddEdge(int x,int y) {

    tree[ptr].v = y;
    tree[ptr].next = head[x],head[x] = &tree[ptr++];
    tree[ptr].v = x;
    tree[ptr].next = head[y],head[y] = &tree[ptr++];
}
void Tree_DP(int v) {

    if (vis[v]) return;
    vis[v] = 1;
    int i,j,k,tot = 0,sum;
    node *p = head[v];


    while (p != NULL) {

        if (!vis[p->v]) {

            Tree_DP(p->v);
            dp[v][1] += dp[p->v][0];
            dp[v][0] += max(dp[p->v][1],dp[p->v][0]);
        }
        p = p->next;
    }
    dp[v][1] += num[v];
}


int main()
{
    int i,j,k,a,b;


    while (scanf("%d",&n) != EOF) {

        Initial();
        for (i = 1; i <= n; ++i)
            scanf("%d",&num[i]);
        while (scanf("%d%d",&a,&b),a+b)
            AddEdge(a,b);

        
        Tree_DP(1);
        printf("%d\n",max(dp[1][0],dp[1][1]));
    }
    return 0;
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值