POJ 1155 TELE 树形背包

链接:http://poj.org/problem?id=1155

题意:电视台转播一场重要的足球比赛,以这个转播机器为根建立一棵“转播树”,数中一共有N个(N<=3000),叶子节点是所有用户,有M个用户(M<=N-1),每个用户有固定的付费额度。除了用户以外的结点都是转接信号的机器,在所有结点之间连线都需要有一定的花费。现在要求我尽可能满足更多人的观看要求,并且保证转播不赔钱。问最多可以保证多少人的观看要求。

思路:从叶到根依次记录当前结点可以满足的观看要求的数量,并且记录满足该数量的最多收益,即对每个结点进行背包DP,保证每次决策的最优化。

状态转移方程:dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]-w),u是当前结点,v是子结点,j是u的一种可以满足的人数,k是已经从v的一种可以满足的人数,dp[v][k]已经先确定过了。w是路径的花费值。对于每个叶子结点dp[u][1]就是u可以付的费用。

代码:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <ctype.h>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define eps 1e-8
#define INF 0x3fffffff
#define maxn 3005
#define PI acos(-1.0)
#define seed 31//131,1313
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
int head[maxn],top,dp[maxn][maxn],t[maxn],N,M,tot,x,y,num[maxn];
void init()
{
    memset(head,-1,sizeof(head));
    for(int i=1; i<=N; i++)
        for(int j=1; j<=N; j++)
            dp[i][j]=-INF;
    memset(t,0,sizeof(t));
    memset(num,0,sizeof(num));
    top=0;
}
struct Edge
{
    int v,w;
    int next;
} edge[maxn];
void add_edge(int u,int v,int w)
{
    edge[top].v=v;
    edge[top].w=w;
    edge[top].next=head[u];
    head[u]=top++;
}
void dfs(int u,int f)
{
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v,w=edge[i].w;
        if(v!=f)
        {
            dfs(v,u);
            num[u]+=num[v];
            for(int j=num[u]; j>=1; j--)
                for(int k=1; k<=min(j,num[v]); k++)
                    if(dp[v][k]!=-INF)
                        dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]-w);
        }
    }
}
int main()
{
    scanf("%d%d",&N,&M);
    init();
    for(int i=1; i<=N-M; i++)
    {
        scanf("%d",&tot);
        for(int j=1; j<=tot; j++)
        {
            scanf("%d%d",&x,&y);
            add_edge(i,x,y);
        }
    }
    for(int i=N-M+1; i<=N; i++)
    {
        scanf("%d",&dp[i][1]);
        num[i]=1;
    }
    dfs(1,1);
    for(int i=num[1]; i>=0; i--)
        if(dp[1][i]>=0)
        {
            printf("%d\n",i);
            break;
        }
    return 0;
}
时间: 2024-10-11 05:35:08

POJ 1155 TELE 树形背包的相关文章

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(树形泛化背包dp)

/* 这道题还不错,自己想出了思路过得也比较快,也得出了一个小经验,以后写这种题先把关键部分伪代码写出来这样会快很多而且 不那么容易出错,省去很多的调试时间 这道题就是转化为一道树形背包问题.首先把需要付的钱转为负数,对每个叶子结点增加一个子节点表示赚的钱,为正数. 然后记录下当前结点的所有可能的用户数目所花费的钱.所以问题就转化为一道简单的树形dp问题.最后找出盈利为非负数的最大 用户数即可. 有一点要注意dp数组初始化为一个很大的负数,刚开始因为这个问题wa了一遍 用到了num数组存放每个结

[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-

树形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 背包型树形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个叶子节点的情况,不会算复杂度,每个非叶子节点中

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 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)

POJ 1155 树形背包

题意:从一个发射站发射电视,只有叶子节点是用户,收到一部分费用,所有的边都有花费,求在不亏本的情况下,最多可以让多少用户(叶子结点)收看到电视. 分析:树形背包. 状态定义: dp(i,j) : 以 i 为根的,让 j 个用户看到电视,最大获益(可以为负数).那么sz不再是原来的定义了. 最后遍历 j,第一个不为负数的就是答案. 状态转移:树形背包,dp(i,j) = max(d(i,j) , dp(i)(k)+dp(son,j-k)-w); #include <algorithm> #inc