码迷,mamicode.com
首页 > 其他好文 > 详细

poj 1155 TELE(树形泛化背包dp)

时间:2015-04-06 08:50:07      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:树形dp

/*
    这道题还不错,自己想出了思路过得也比较快,也得出了一个小经验,以后写这种题先把关键部分伪代码写出来这样会快很多而且
    不那么容易出错,省去很多的调试时间
    这道题就是转化为一道树形背包问题。首先把需要付的钱转为负数,对每个叶子结点增加一个子节点表示赚的钱,为正数.
    然后记录下当前结点的所有可能的用户数目所花费的钱.所以问题就转化为一道简单的树形dp问题。最后找出盈利为非负数的最大
    用户数即可.
    有一点要注意dp数组初始化为一个很大的负数,刚开始因为这个问题wa了一遍
    用到了num数组存放每个结点的叶子结点的数目,起到很好的优化作用。
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<iostream>
using namespace std;
#define maxn 6005
int dp[maxn][maxn],num[maxn],val[maxn];
vector<int>sons[maxn];
//num对于优化起了很大的作用,来记录当前结点子树中的叶子结点数目
void dfs(int rt){
    dp[rt][0]=0;
    for(int u=0;u<sons[rt].size();u++){
        int s=sons[rt][u];
        dfs(s);
        num[rt]+=num[s];
        for(int i=num[rt]-num[s]+1;i<=num[rt];i++) dp[rt][i]=-1000000;  //要初始化为一个很大的负数
        for(int i=num[rt];i>=1;i--){
            for(int j=1;j<=num[s]&&j<=i;j++){
                dp[rt][i]=max(dp[rt][i],dp[s][j]+dp[rt][i-j]+val[s]);
            }
        }
    }
}
void init(){
    for(int i=0;i<maxn;i++) sons[i].clear();
    memset(val,0,sizeof(val));
    memset(num,0,sizeof(num));
}
void print(){
    for(int i=num[1];i>=0;i--)
        if(dp[1][i]>=0)
        {printf("%d\n",i);break;}
}
int main(){
    int i,j,n,m,k,a,b;
    while(~scanf("%d%d",&n,&m)){
        init();
        for(i=1;i<=n-m;i++){
            scanf("%d",&k);
            for(j=1;j<=k;j++){
                scanf("%d%d",&a,&b);
                sons[i].push_back(a);
                val[a]=-b;
            }
        }
        for(i=n+1;i<=n+m;i++){      //给每一个叶子结点加一个结点,用它来表示赚的钱,而其它点都表示需要支付的钱
            scanf("%d",&val[i]);
            num[i]=1;
            sons[i-m].push_back(i);
        }
        dfs(1);
        print();
    }
    return 0;
}


poj 1155 TELE(树形泛化背包dp)

标签:树形dp

原文地址:http://blog.csdn.net/crazy__c/article/details/44894439

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!