hdu1011 http://acm.hdu.edu.cn/showproblem.php?pid=1011
给定n个洞穴和m个士兵(每个士兵能消灭20个bugs)
然后给定每个洞穴的bugs数量(背包的费用)和brain的数量(背包的价值)
然后给定n-1条边,使得n个洞穴形成一课树
问能取得的brain数量的最大值。
思路:其实就是在树上面进行背包问题的求解,只不过是有依赖的背包(儿子要选,当且仅当父亲也被选)
普通的01背包是这样
for(i=每件物品)
for(j=每个容量)
dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);
即对于每个物品,求出各个容量的背包对于第i件物品处理完之后的最大值。
那么在树上面进行背包问题,同样要是这样。
第一个循环:
但是因为背包是树形的,所以不能用循环来遍历背包,要用dfs来进行遍历
第二个循环:
因为是有依赖的背包问题,儿子要选,当且仅当父亲也被选。所以我们要枚举父亲的容量和儿子的容量进行状态转移(即两重循环)
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 typedef long long LL; 15 const int INF = 1<<30; 16 const int N = 100+10; 17 struct Cave 18 { 19 int bugs,brain; 20 }cave[N]; 21 int dp[N][N]; 22 struct Edge 23 { 24 int v,next; 25 }g[N<<1]; 26 int head[N],e; 27 28 /* 29 背包? 30 有依赖的背包 31 容量为m 32 费用为bugs的数量, 价值为brain的数量 33 对于每个洞穴,选或者不选 34 这个洞穴要选,当且仅当父亲被选 35 */ 36 bool vis[N]; 37 int m; 38 void dfs(int u, int fa) 39 { 40 vis[u] = true; 41 int t = (cave[u].bugs+19)/20; 42 for(int i=t; i<=m; ++i) 43 dp[u][i] = cave[u].brain; 44 for(int i=head[u]; i!=-1; i=g[i].next) 45 { 46 int v = g[i].v; 47 if(vis[v]) continue; 48 dfs(v,u); 49 for(int j=m; j>=t; --j)//必须从后往前推??? 由转移方程可以看出,前面的状态依赖于后面的状态,所以要求出后面的状态 50 for(int k=1; k+j<=m; ++k)//所有可能的情况都要枚举,然后求出最大值 51 dp[u][j+k] = max(dp[u][j+k],dp[u][j]+dp[v][k]); 52 53 54 } 55 } 56 void init(int n) 57 { 58 for(e=0; e<=n; ++e) 59 { 60 head[e] = -1; 61 vis[e] = false; 62 } 63 e = 0; 64 } 65 void addEdge(int u, int v) 66 { 67 g[e].v = v; 68 g[e].next = head[u]; 69 head[u] = e++; 70 } 71 int main() 72 { 73 int n,i,u,v; 74 while(scanf("%d%d",&n,&m),n!=-1) 75 { 76 init(n); 77 for(i=1; i<=n; ++i) 78 scanf("%d%d",&cave[i].bugs,&cave[i].brain); 79 for(i=1; i<n; ++i) 80 { 81 scanf("%d%d",&u,&v); 82 addEdge(u,v); 83 addEdge(v,u); 84 } 85 if(m==0) 86 { 87 puts("0"); 88 continue; 89 } 90 memset(dp,0,sizeof(dp)); 91 dfs(1,-1); 92 printf("%d ",dp[1][m]); 93 } 94 return 0; 95 }
样例: