DP专题·四(树形dp)

Posted 萌萌的美男子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
View Code

 

以上是关于DP专题·四(树形dp)的主要内容,如果未能解决你的问题,请参考以下文章

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

动态规划-树形DP-树上背包专题

动态规划专题

树形动规专题

树形DP小结

动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索