HDU 1011 Starship Troopers星河战队(树形dp)

题意

  有n个洞穴编号为1~n,洞穴间有通道,形成了一个n-1条边的树, 洞穴的入口即根节点是1。
  每个洞穴有x只bugs,并有价值y的金子,全部消灭完一个洞穴的虫子,就可以获得这个洞穴的y个金子.
  现在要派m个战士去找金子,从入口进入。每次只有消灭完当前洞穴的所有虫子,才可以选择进入下一个洞穴。
  一个战士可以消灭20只虫子,如果要杀死x只虫子,那么要x/20向上取整即(x+19)/20个战士。
  如果要获得某个洞穴的金子,必须留下足够杀死所有虫子的战士数量, 即(x+19)/20个战士,然后这些留下战士就不能再去其它洞穴
  其他战士可以继续走去其它洞穴,可以选择分组去不同的洞穴。
  战士只能往洞穴深处走,不能走回头路。
  问最多能获得多少金子?

 思路:

  基础的树形DP。

  要特别注意的是,如果某个节点的bug数为0,而金子不为0,那么仍然需要派1个人以上去捡,而不是花0个士兵就能获得该点的金子。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N=110;
 4 vector<int> vect[N];
 5 int bug[N], num[N], dp[N][N], n, m;
 6 
 7 void DFS(int t,int far,int peo)
 8 {
 9     int need=(bug[t]+19)/20;
10     if(peo<need || peo==0)    return ;
11 
12     for(int i=need; i<=peo; i++)    dp[t][i]=num[t];    //若有士兵i>=need个,那么起码拿到本节点的金子
13     for(int i=0; i<vect[t].size(); i++)
14     {
15         int to=vect[t][i];
16         if(to^far)
17         {
18             DFS(to, t, peo-need);
19             for(int j=peo; j>need; j--)         //到达本节点可能的人数。
20                 for(int k=1; k<=j-need; k++)    //给孩子to分配k个士兵。
21                     dp[t][j]=max(dp[t][j],dp[t][j-k]+dp[to][k]);
22         }
23     }
24 }
25 
26 
27 int main()
28 {
29     freopen("input.txt","r",stdin);
30     int u,v;
31     while(scanf("%d%d",&n,&m), n+m>0)
32     {
33         for(int i=0; i<=n; i++)    vect[i].clear();
34         memset(dp,0,sizeof(dp));
35 
36         for(int i=1; i<=n; i++)      //房间里的bug数、金子
37             scanf("%d%d",&bug[i],&num[i]);
38         for(int i=1; i<n; i++)            //连通情况
39         {
40             scanf("%d%d",&u,&v);
41             vect[u].push_back(v);
42             vect[v].push_back(u);
43         }
44         DFS(1, -1, m);
45         printf("%d
", dp[1][m]);
46     }
47     return 0;
48 }
AC代码
原文地址:https://www.cnblogs.com/xcw0754/p/4241459.html