[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-j]+dp[v][j]-cost[u][v]);

用java写了一个版本。。总是RE,就不知道是为什么了。。

代码:

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <vector>
  6 using namespace std;
  7
  8 const int MAX_N = 3333;
  9 const int INF = 99999999;
 10 struct EDGE{
 11     int to,cost;
 12     int next;
 13 };
 14 EDGE edge[MAX_N<<1];
 15 int ptr,head[MAX_N];
 16 int cost[MAX_N];
 17
 18 void init(){
 19     memset(edge,-1,sizeof(edge));
 20     memset(head,-1,sizeof(head));
 21     ptr = 0;
 22 }
 23
 24 void add_edge(int from,int to,int cost){
 25     edge[ptr].to = to;
 26     edge[ptr].cost = cost;
 27     edge[ptr].next = head[from];
 28     head[from] =  ptr++;
 29 }
 30
 31 int N,M;
 32 int dp[MAX_N][MAX_N];
 33 bool vis[MAX_N];
 34 int sum[MAX_N];
 35
 36 void DP(int u){
 37     if( vis[u] ) return;
 38     vis[u] = true; dp[u][0] = 0;
 39     int tot = 0;
 40
 41     for(int i=head[u];~i;i=edge[i].next){
 42         int v = edge[i].to;
 43         if( !vis[v] ){
 44             tot++;
 45             DP( v );
 46             sum[u] += sum[v];
 47         }
 48     }
 49
 50     if( tot==0 ){
 51         sum[u] = 1;
 52         dp[u][1] = cost[u];
 53     } else {
 54         for(int k=head[u];~k;k=edge[k].next){
 55             int v = edge[k].to;
 56             for(int j=sum[u];j>=1;--j){
 57                 for(int i=1;i<=sum[v];i++){
 58                     if( j>=i && dp[u][j-i]!=-INF && dp[v][i]!=-INF){
 59                         dp[u][j] = max(dp[u][j],dp[u][j-i]+dp[v][i]-edge[k].cost);
 60                     }
 61                 }
 62             }
 63         }
 64     }
 65 }
 66
 67 int main(){
 68     while(scanf("%d%d",&N,&M)!=EOF){
 69         init();
 70         int k;
 71         for(int i=1;i<=N-M;i++){
 72             scanf("%d",&k);
 73             for(int j=0;j<k;j++){
 74                 int a,c;
 75                 scanf("%d%d",&a,&c);
 76                 add_edge(i,a,c);
 77                 add_edge(a,i,c);
 78             }
 79         }
 80
 81         for(int i=N-M+1;i<=N;i++){
 82             scanf("%d",&cost[i]);
 83         }
 84
 85         memset(vis,0,sizeof(vis));
 86         memset(sum,0,sizeof(sum));
 87         for(int i=0;i<=N;i++){
 88             for(int j=0;j<=N;j++){
 89                 dp[i][j] = -INF;
 90             }
 91         }
 92         DP(1);
 93         for(int i=N;i>=0;--i){
 94             if( dp[1][i] >=0 ) {
 95                 printf("%d\n",i);
 96                 break;
 97             }
 98         }
 99
100     }
101     return 0;
102 }
时间: 2024-08-18 10:50:33

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

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

POJ 1155 TELE 树形背包

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

POJ 2342 (树形DP)

Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3863   Accepted: 2172 Description There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure

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 树状dp

TELE Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3856   Accepted: 2054 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 1849 Two (树形dp 树的直径 两种方法)

Two Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 1232   Accepted: 619 Description The city consists of intersections and streets that connect them. Heavy snow covered the city so the mayor Milan gave to the winter-service a list of st

poj 1947 经典树形dp

经典树形dp:问在一棵树上最少删除多少条边可以分离出一个节点数为p的子树. 定义状态: dp[i][j]表示从i为根的子树上分离出一个节点数为j的子树的代价(最少需要删除的边数). 考虑i节点的每个儿子ii,ii可以选或者不选(切断),然后就转化成了背包问题. dp[u][j] = min( dp[u][j], dp[u][j - k] + dp[v][k] ); 1 #include <iostream> 2 #include <cstring> 3 #include <c