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 }
以上是关于DP专题·四(树形dp)的主要内容,如果未能解决你的问题,请参考以下文章