HDU 1011-Starship Troopers(树形背包)

时间:2022-10-13 18:44:27

题意:

有n个洞,连接像一棵树,每个包含一定数量的怪和价值,给你m个士兵,每个士兵能打20个怪,杀完一个洞的怪可得该洞的价值才可继续打相连的下面的洞(每个士兵只能打一个洞),求获得的最大价值。

分析:把士兵数看做容量,就是背包问题,dp[i][j]以i为根节点子树士兵数j时获得的最大价值(根节点有一定的士兵,要先打通根节点)1是根节点

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <complex>
#include <cassert>
#include <utility>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
#define lson l,m,rt<<1
#define pi acos(-1.0)
#define rson m+1,r,rt<<11
#define All 1,N,1
#define read freopen("in.txt", "r", stdin)
const ll  INFll = 0x3f3f3f3f3f3f3f3fLL;
const int INF= 0x7ffffff;
const int mod =  1000000007;
vector<int>e[110];
int used[110],dp[110][110],p[110],b[110];
int n,m;
void dfs(int root){
    int tmp=(b[root]+19)/20;//打通根节点需士兵数
    for(int k=tmp;k<=m;++k)
        dp[root][k]=p[root];
    used[root]=1;
    for(int i=0;i<e[root].size();++i){
        int son=e[root][i];
        if(used[son])continue;
        dfs(son);
        for(int j=m;j>=tmp;--j)
            for(int l=1;l<=j-tmp;++l)
        dp[root][j]=max(dp[root][j],dp[root][j-l]+dp[son][l]);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
            if(n==-1&&m==-1)break;
        for(int i=1;i<=n;++i){
            scanf("%d%d",&b[i],&p[i]);
            e[i].clear();
        }
        memset(dp,0,sizeof(dp));
        memset(used,0,sizeof(used));
        int u,v;
        for(int i=0;i<n-1;++i){
            scanf("%d%d",&u,&v);
            e[u].push_back(v);
            e[v].push_back(u);
        }
        if(m==0)printf("0\n");
        else{
        dfs(1);
        printf("%d\n",dp[1][m]);
        }
    }
return 0;
}