DP专题·四(树形dp)

1、poj 115 TELE

  题意:一个树型网络上有n个结点,1~n-m为信号传送器,n-m+1~n为观众,当信号传送给观众后,观众会付费观看,每铺设一条道路需要一定费用。现在求以1为根,使得收到观众的费用-铺设道路的费用>=0的情况下,能最多给多少个观众观看?

  思路:树形dp,dp[i][j]表示以i为根的子树中选择j个观众(叶子)最大的收益。

  ①如果当前结点为叶子结点,那么其dp[i][0]=0,dp[i][1]=val[i].

  ②如果为其他结点,则dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[son][k]-cost)(i:max->0;j:0->max)(表示当前结点选j个叶子,其中k个叶子来自son这棵子树).每个结点的容量为以其为根的子树的所有叶结点数目,可以通过dp回溯累加。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn = 3010;
 7 const int maxe = 6020;
 8 const int INF = 0x3f3f3f;
 9 int wson[maxn];//以i为根的子树的容量(可选的叶子数目)
10 int val[maxn];
11 struct edge
12 {
13     int from, to, cost, next;
14     edge(int ff=0,int tt=0,int cc=0,int nn=0):from(ff),to(tt),cost(cc),next(nn){ }
15 }Edge[maxe];
16 int Head[maxn],totedge;
17 int n, m;//1为根,2~n-m为传送器,n-m+1~n为观众(叶子)
18 int dp[maxn][maxn];//dp[i][j]表示以i为子树选择j个叶子的最大v(叶子值-路值)
19 bool vis[maxn];//表示该点是否已经经过
20
21 void Init()
22 {
23     memset(Edge, 0, sizeof(Edge));
24     memset(Head, -1, sizeof(Head));
25     memset(dp, -INF, sizeof(dp));
26     memset(vis, 0, sizeof(vis));
27     totedge = 0;
28 }
29
30 void DP(int now, int pre)
31 {
32     vis[now] = true;
33     if (now >= n - m + 1)
34     {//如果为叶子
35         dp[now][0]=0,dp[now][1] = val[now], wson[now] = 1;
36         return;
37     }
38     else dp[now][0] = 0;
39     for (int e = Head[now]; e != -1; e = Edge[e].next)
40     {
41         int u = Edge[e].to, w = Edge[e].cost;
42         if (vis[u]) continue;
43         DP(u, now);
44         wson[now] += wson[u];
45         for (int j = wson[now]; j >= 1; j--)
46         {//枚举当前结点选择叶子个数(从大往小,01背包)
47             for (int k = 1; k <= min(wson[u],j); k++)
48             {//枚举子节点的叶子个数
49                 dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[u][k] - w);
50             }
51         }
52     }
53 }
54
55 void AddEdge(int from, int to, int cost)
56 {
57     Edge[++totedge] = edge(from, to, cost,Head[from]);
58     Head[from] = totedge;
59     Edge[++totedge] = edge(to, from, cost, Head[to]);
60     Head[to] = totedge;
61 }
62
63 int main()
64 {
65     while (~scanf("%d%d", &n, &m))
66     {
67         Init();
68         for (int i = 1; i <= n - m; i++)
69         {
70             int k;
71             scanf("%d", &k);
72             for (int j = 1; j <= k; j++)
73             {
74                 int to, v;
75                 scanf("%d%d", &to, &v);
76                 AddEdge(i, to, v);
77             }
78         }
79         for (int i = n - m + 1; i <= n; i++) scanf("%d", val + i);
80         DP(1, 0);
81         for (int i = m; i >= 0; i--)
82         {
83             if (dp[1][i] >= 0)
84             {
85                 printf("%d\n",i);
86                 break;
87             }
88         }
89     }
90     return 0;
91 }

时间: 2024-07-30 07:38:23

DP专题·四(树形dp)的相关文章

【DP】树形DP 记忆化搜索

DP中的树形DP,解决方法往往是记忆化搜索.显然,树上递推是很困难的.当然做得时候还是得把状态定义和转移方程写出来:dp[u][1/0]表示以u为根节点的树 涂(1) 或 不涂(0) 颜色的最少方案数.树上DP有两个经典问法:一条边两端至少有个一个端点涂色,问整个tree最少涂色次数:还有一种忘了...此题是前种问法. #include<cstdio> #include<cstring> #include<algorithm> using namespace std;

树形dp 入门

今天学了树形dp,发现树形dp就是入门难一些,于是好心的我便立志要发一篇树形dp入门的博客了. 树形dp的概念什么的,相信大家都已经明白,这里就不再多说.直接上例题. 一.常规树形DP P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以

树形dp摸瞎历程

树形\(dp\)摸瞎历程 前言: 什么是树形\(dp\)? 简而言之,树形dp,就是在树形结构上的动态规划,由于树形结构具有一定的特点,可以描述比较复杂的关系,再加上树的递归定义,是一种非常合适动规的框架,属于动规中很特殊的一种类型. 如何实现树形\(dp\)? 树形dp的状态表示中,第一位通常是节点编号(代表以该节点为根的子树),大多数时候,我们采用递归的方式实现树形动态规划.对于每个节点x,我们先递归x的所有子节点,并在其子节点上dp,在回溯时,从子节点向节点x进行状态转移. 树形\(dp\

机房测试13:dp专题(单调队列+树形背包+记忆化搜索)

T1: 很容易写出dp式子:定义dp[i][j]为现在是第i个烟火,位置在j,然后就可以枚举上一个时间的位置k转移过来.(j-(t[i]-t[i-1])*d <= k <=j+(t[i]-t[i-1])*d) 这样是n*n*m的,考虑优化. 固定一个边界:j-(t[i]-t[i-1])*d<=k 可以发现,当j变大,k的范围会变小,于是就可以维护一个单调递减的队列,队头就是答案. 而另外一个边界同理,只需要反过来做一遍就可以了. 注意: 1. 开滚动数组!!否则爆空间 2.不需要初始化负

hdu5593--ZYB&#39;s Tree(树形dp)

问题描述 ZYB有一颗N个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,B,令fai??为节点i的父亲,fa?1??=0;fa?i??=(A∗i+B)%(i−1)+1,i∈[2,N] . 输出:输出时只需输出N个点的答案的xor和即可. 输入描述 第一行一个整数TT表示数据组数. 接下来每组数据: 一行四个正整数N,K,A,

Gym 100962J Jimi Hendrix (树形DP)

题意:给定一棵树,然后每条边有一个字母,然后给定一行字符串,问你能不能从这棵树上找到,并输出两个端点. 析:树形DP,先进行递归到叶子结点,然后再回溯,在回溯的时候要四个值,一个是正着匹配的长度和端点,一个是反着匹配的长度和端点, 然后一个一个匹配,并不断更新这个长度和端点. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string&

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

DP专题

DP专题 1. 背包模型 2. 子序列模型 3. 递推DP 4. 区间DP 5. 树形DP 6. 状压DP 学习资料:位操作基础篇之位操作全面总结 如何快速取得一个二进制状态的所有子状态 7. 概率DP 学习资料:简说期望类问题的解法 等等.......

hdu5593/ZYB&#39;s Tree 树形dp

ZYB's Tree Memory Limit: 131072/131072 K (Java/Others) 问题描述 ZYBZYB有一颗NN个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,BA,B,令fa_ifa?i??为节点ii的父亲,fa_1=0fa?1??=0;fa_i=(A*i+B)\%(i-1)+1fa