HDU 1011 Starship Troopers (树dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011

题意:

        题目大意是有n个房间组成一棵树,你有m个士兵,从1号房间开始让士兵向相邻的房间出发,每个房间里有一个代价,代价是值/20个士兵,

同时有一个价值,问你花费这m个士兵可以得到的最大价值是多少。

思路:

        树上背包,这题比较坑爹。士兵为0,输出0。要是一个房间的cost不足20的倍数也要补全20的倍数。

        dp[i][j]表示以i节点为子树的root使用j个士兵的最大价值( 不用管父节点 ),dp[i][j] = max(dp[i][j] , dp[i.son][k] + dp[i][j - k])

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 105;
 7 int cost[N], val[N];
 8 vector <int> G[N];
 9 int dp[N][N], n, m;
10 
11 void dfs(int u, int p) {
12     int temp = (cost[u] + 19) / 20;
13     if(temp > m)
14         return ;
15     for(int i = temp; i <= m; ++i) {
16         dp[u][i] = val[u];
17     }
18     for(int i = 0; i < G[u].size(); ++i) {
19         int v = G[u][i];
20         if(v == p)
21             continue;
22         dfs(v, u);
23         for(int j = m; j >= temp + 1; --j) { //类似背包 每个可取的值只枚举一次
24             for(int k = temp; k < j; ++k) { //每条路径上会保证有一个士兵
25                 dp[u][j] = max(dp[u][j], dp[u][k] + dp[v][j - k]);
26             }
27         }
28     }
29 }
30 
31 int main()
32 {
33     while(~scanf("%d %d", &n, &m)) {
34         if(m == -1 && n == -1)
35             break;
36         memset(dp, 0, sizeof(dp));
37         for(int i = 1; i <= n; ++i) {
38             G[i].clear();
39             scanf("%d %d", cost + i, val + i);
40         }
41         int u, v;
42         for(int i = 1; i < n; ++i) {
43             scanf("%d %d", &u, &v);
44             G[u].push_back(v);
45             G[v].push_back(u);
46         }
47         dfs(1, -1);
48         if(!m) {
49             printf("0\n");
50         } else {
51             printf("%d\n", dp[1][m]);
52         }
53     }
54     return 0;
55 }

 

posted @ 2016-10-09 20:17  Recoder  阅读(300)  评论(0编辑  收藏  举报