poj 1155 TELE(树形泛化背包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;
}

时间: 2024-10-24 00:03:14

poj 1155 TELE(树形泛化背包dp)的相关文章

POJ 1155 TELE 树形背包问题

题目描述看的莫名其妙,很久才看懂. 就是很裸的树形背包问题吧,状态是dp(i,j)表示节点i取到j个客户能得到的最大收益. 注意一开始初始化的时候所有j为0的时候应该是0,然后其他值都要初始化成负无穷,因为收益有可能是负值. 然后做01背包的时候注意方向,防止出现取某一个元素多次 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set&g

POJ 1155 TELE 树形背包

链接:http://poj.org/problem?id=1155 题意:电视台转播一场重要的足球比赛,以这个转播机器为根建立一棵"转播树",数中一共有N个(N<=3000),叶子节点是所有用户,有M个用户(M<=N-1),每个用户有固定的付费额度.除了用户以外的结点都是转接信号的机器,在所有结点之间连线都需要有一定的花费.现在要求我尽可能满足更多人的观看要求,并且保证转播不赔钱.问最多可以保证多少人的观看要求. 思路:从叶到根依次记录当前结点可以满足的观看要求的数量,并且

[POJ 1155] TELE (树形dp)

题目链接:http://poj.org/problem?id=1155 题目大意:电视台要广播电视节目,要经过中转机构,到观众.从电视台到中转商到观众是一个树形结构,经过一条边需要支付成本.现在给你每两个节点之间传播的成本,给你每个观众会付的钱,问你电视台在不亏本的情况下最多能给多少个观众看节目. 这是我的第一道树形dp..无耻的看了题解.. 设计状态:dp[u][i]代表以u为根的子树中有i个观众,能够得到的最大收入. 状态转移:dp[u][i] = max(dp[u][i],dp[u][i-

POJ 1155 TELE 背包型树形DP 经典题

由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送数据到达另一个节点,电视台需要一定的费用 若可以传送数据到达用户的节点n-m+1~n,这些用户各自愿意支付一定的费用给电视台 现在电视台希望在不亏本的情况下为尽量多的用户转播比赛 输出最多可以为多少用户转播比赛 背包类型的树形DP第一题 dp[i][j]表示以节点i为根的子树有j个用户获得转播,电视

POJ 1155 TELE (树形DP,树形背包)

题意:给定一棵树,n个节点,其中有m个叶子表示的是用户,其他点表示中转器, 每条边都有权值,每个用户i愿意给的钱w[i],问如果在不亏钱的情况下能为多少用户转播足球比赛? 思路: 其实就是要选出部分叶子节点,其花费=所选叶子权值 - 经过的所有边权(每条边只算1次花费). 那么对于每个节点,可以考虑在其子树下选择1~k个叶子节点,记录下dp值(是个最优值).那么就需要枚举所有可能了.复杂度貌似在极端情况下还是挺高的,比如单链1000个节点+2000个叶子节点的情况,不会算复杂度,每个非叶子节点中

树形DP [POJ 1155] TELE

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3787   Accepted: 2007 Description A TV-network plans to broadcast an important football match. Their network of transmitters and users can be represented as a tree. The root of the tre

POJ 1155 TELE

TELE Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 115564-bit integer IO format: %lld      Java class name: Main A TV-network plans to broadcast an important football match. Their network of transmitters an

POJ 1742 Coins 【多重背包DP】

题意:有n种面额的硬币.面额.个数分别为A_i.C_i,求最多能搭配出几种不超过m的金额? 思路:dp[j]就是总数为j的价值是否已经有了这种方法,如果现在没有,那么我们就一个个硬币去尝试直到有,这种价值方法有了的话,那么就是总方法数加1.多重背包可行性问题 传统多重背包三重循环会超时,因为只考虑是否可行,没有考虑剩余面额数量的因素. o(n*v)方法 #include <iostream> #include <cstdio> #include <string.h> #

POJ 1155 (树形DP+背包)

题目链接: http://poj.org/problem?id=1155 题目大意:电视台转播节目.对于每个根,其子结点可能是用户,也可能是中转站.如果是中转站则花钱,如果是用户,则收钱.问在不亏本的前提下最多能有多少个用户看到节目. 解题思路: 树形背包.cost=1. 且有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]. 本题是cost=1的特殊背包问题,在两个for循环上有一个优化. for(f+1...j....cost) for(1....k...j-cost)