HDU 1011 Starship Troopers(树上背包)

 

题目大意

 

有 n(1<n<=100) 个山洞,每个山洞中都有一些 bug,每个山洞中都有一定的概率包含一个 brain。所有的山洞形成一棵树

现在给你 m(0<=m<=100) 个士兵,每个士兵都能消灭 20 个 bugs,并占领这个山洞

山洞的入口的编号是 1

问怎么安排士兵占领山洞才能使捕获 brain 的概率最大!

 

做法分析

 

典型的树上背包问题

定义状态 f[u][P] 表示用 P 个士兵占领以 u 为根节点的子树所能获得的概率最大值

状态转移就是一个树形DP过程

目标状态就是 f[1][m]

 

一个小trick:即使某个山洞的 bug 数量为 0,那么也至少需要 1 个士兵去获取 brain,所以当现在手上的士兵数量为 0 的时候,可以直接输出 0 了

 

参考代码

 

PS:我把所有点的编号都 -1 了

HDU 1011
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 
 6 using namespace std;
 7 
 8 const int N=101;
 9 
10 int n, m;
11 int bug[N], p[N], f[N][N];
12 vector<int> adj[N];
13 
14 void DFS(int u, int pre)
15 {
16     for(int i=bug[u]; i<=m; i++) f[u][i]=p[u];
17     int tot=(int)adj[u].size();
18     for(int i=0; i<tot; i++)
19     {
20         int v=adj[u][i];
21         if(v==pre) continue;
22         DFS(v, u);
23         for(int j=m; j>=bug[u]; j--)
24             for(int k=1; k<=j-bug[u]; k++)
25                 if(f[u][j]<f[u][j-k]+f[v][k]) f[u][j]=f[u][j-k]+f[v][k];
26     }
27 }
28 
29 int main()
30 {
31     while(scanf("%d%d", &n, &m), n!=-1 || m!=-1)
32     {
33         for(int i=0; i<n; i++)
34         {
35             scanf("%d%d", &bug[i], &p[i]);
36             bug[i]=(bug[i]+19)/20;
37         }
38         for(int i=0; i<n; i++) adj[i].clear();
39         for(int i=0, a, b; i<n-1; i++)
40         {
41             scanf("%d%d", &a, &b);
42             adj[a-1].push_back(b-1);
43             adj[b-1].push_back(a-1);
44         }
45         if(m==0)
46         {
47             printf("0\n");
48             continue;
49         }
50         memset(f, 0, sizeof f);
51         DFS(0, -1);
52         printf("%d\n", f[0][m]);
53     }
54     return 0;
55 }

 

AC通道

 

HDU 1011 Starship Troopers

 

 

 

posted @ 2013-03-09 11:04  jianzhang.zj  阅读(1086)  评论(0编辑  收藏  举报