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

题意:给定一棵树,n个节点,其中有m个叶子表示的是用户,其他点表示中转器, 每条边都有权值,每个用户i愿意给的钱w[i],问如果在不亏钱的情况下能为多少用户转播足球比赛?

思路:

  其实就是要选出部分叶子节点,其花费=所选叶子权值 - 经过的所有边权(每条边只算1次花费)。

  那么对于每个节点,可以考虑在其子树下选择1~k个叶子节点,记录下dp值(是个最优值)。那么就需要枚举所有可能了。复杂度貌似在极端情况下还是挺高的,比如单链1000个节点+2000个叶子节点的情况,不会算复杂度,每个非叶子节点中有两个for循环,全按上限来算接近O(n3)。

 1 //#include <bits/stdc++.h>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #define pii pair<int,int>
 6 #define INF 0x3f3f3f3f
 7 #define LL long long
 8 using namespace std;
 9 const int N=3010;
10
11 struct node
12 {
13     int from,to,val,next;
14     node(){};
15     node(int from,int to,int val,int next):from(from),to(to),val(val),next(next){};
16 }edge[N*2];
17 int head[N], n, m, edge_cnt;
18 void add_node(int from,int to,int val)
19 {
20     edge[edge_cnt]=node(from,to,val,head[from]);
21     head[from]=edge_cnt++;
22 }
23
24 int dp[N][N], mon[N];
25 int DFS(int t,int cost)
26 {
27     node e;
28     int sum=dp[t][0]=0;
29     for(int i=head[t]; i!=-1; i=e.next)
30     {
31         e=edge[i];
32         int tmp=DFS(e.to, cost+e.val);
33         sum+=tmp;   //统计叶子数量
34
35         for(int j=sum; j>0; j--)    //必须降序,防止重复。
36             for(int k=1; k<=tmp&&k<=j; k++)   //在此子树中挑k个叶子节点。升序/降序皆可,但需稍修改。
37                 dp[t][j]=max(dp[t][j], dp[t][j-k]+dp[e.to][k]-e.val ); //dp值表示花费
38     }
39     if(sum==0)
40     {
41         dp[t][1]=mon[t];
42         sum=1;
43     }
44     return sum;
45 }
46
47 int main()
48 {
49     //freopen("input.txt", "r", stdin);
50     int a,b;
51     while(~scanf("%d%d",&n,&m))
52     {
53         memset(head, -1, sizeof(head));
54         for(int i=0; i<=n; i++)
55             for(int j=0; j<=n; j++)
56                 dp[i][j]=-INF;
57
58         for(int i=1,y; i<=n-m; i++) //i点的后继和边权
59         {
60             scanf("%d",&y);
61             while(y--)
62             {
63                 scanf("%d%d",&a,&b);
64                 add_node(i,a,b);
65             }
66         }
67         for(int i=n-m+1; i<=n; i++) //用户肯交的钱
68             scanf("%d",&mon[i]);
69
70         DFS(1,0);
71         for(int i=m; i>=0; i--)
72             if(dp[1][i]>=0) {printf("%d\n",i); break;}
73     }
74     return 0;
75 }
76
77 AC代码

AC代码

时间: 2024-10-05 15:28:55

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 3345 Bribing FIPA 【树形dp + 01背包】

Bribing FIPA Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4274   Accepted: 1337 Description There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (Interna

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on

hdu 1561The more, The Better(树形dp&amp;01背包)

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 4949    Accepted Submission(s): 2918 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝

HDU ACM 4044 GeoDefense -&gt;树形DP+分组背包

题意:地图是一个编号为1-n的节点的树,节点1是敌方基地,其他叶节点是我方基地.敌人基地会出来敌人,为了防止敌人攻进我方基地,我们可以选择造塔.每个节点只能造一个塔,节点i有ki种塔供选择,价值和攻击力为price_i, power_i,攻击力power_i是让敌人经过这个节点时让敌人的HP减少power_i点.因此从敌人基地到我方任意一个基地的路径,这条路径上所有塔的攻击力之和,就是这个基地的抵抗力. 敌人攻击路径不确定,为了保护我方所有基地,需要确定所有基地中抵抗力最低的一个.我方只有数量为

hdu 4044 GeoDefense (树形dp+01背包)

GeoDefense Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 663    Accepted Submission(s): 267 Problem Description Tower defense is a kind of real-time strategy computer games. The goal of towe

[P1273] 有线电视网 (树形DP+分组背包)

题意:给出一棵树,有边权,只有叶子节点有点权,求一个合法方案(选择走到哪几个叶子节点,且路径上的权值和 <= 要走到的叶子节点的点权和),使得选择的叶子节点数量尽量的多: 解法:树形DP+分组背包: 1.树形DP:这是一棵树,所以叫树形DP: 2.分组背包:在这里主要是运用到了它的思想:我们可以设 f[i][j],表示 i节点选择了 j个叶子节点的费用最大值:假设现在在 x节点,它的下面有 n个叶子节点(不是它的儿子),那么我们就要处理出它选 1,2,3,……,n 个叶子节点的情况,但是由于这是

poj 1837 Balance (dp,01背包)

链接:poj 1837 题意:有一个天平,天平左右两边各有若干个钩子,总共有C个钩子,有G个钩码, 求将钩码挂到钩子上使天平平衡的方法的总数.其中可以把天枰看做一个以x轴0点作为平衡点的横轴 分析:力臂=重量 *臂长 = g[i]*c[j] 当平衡度k=0时,说明天枰达到平衡,k>0,说明天枰倾向右边(x轴右半轴),k<0则左倾 因此可以定义一个 状态数组dp[i][k],意为在挂满前i个钩码时,平衡度为k的挂法的数量. 由于距离c[i]的范围是-15~15,钩码重量的范围是1~25,钩码数量

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)

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