Hdu 1011 Starship Troopers 树形dp

又是一道树状dp题目,感觉好难,看的网上的解析才做出来,不过比第一次遇到这种题目时要好多了,加油,多遇到几次就会了。

 

 

 

代码:

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int MAX = 105;

int dp[MAX][MAX];
int bug[MAX], brain[MAX];
int n, m;
int vis[MAX]; 
vector<int> tree[MAX];        //

void dfs(int root);

int main(){
//    freopen("input.txt", "r", stdin);
    
    while(cin >> n >> m && n != -1){
        for(int i=1; i<=n; i++){
            cin >> bug[i] >> brain[i];
            bug[i] = (bug[i] + 19) / 20;    //转化为需要消耗多少战士,向上取整
            tree[i].clear(); 
        }
        for(int i=1; i<n; i++){
            int u, v;
            cin >> u >> v;
            tree[u].push_back(v);
            tree[v].push_back(u);
        }
        
        if(m == 0){
            cout << 0 << endl;    continue;
        }
        
        memset(vis, 0, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        dfs(1);
        
        cout << dp[1][m] << endl;
    }
    
    return 0;
} 

void dfs(int root){
    vis[root] = 1;
    
    if(m < bug[root])
        return;
    
    for(int i=bug[root]; i<=m; i++){
        dp[root][i] = brain[root];        //当军队数大于等于bug[root],则至少可以获取到 brain [root] 的大脑 
    }
    
    for(int i=0; i<tree[root].size(); i++){
        int v = tree[root][i];
        if(vis[v])            //区分根结点与子节点,v 一定是当前树的祖先 
            continue;
        dfs(v);            //将子树的状态数组填充好 
        //DP,在root中 k 个战士,子树中  j-k 个战士时的最大值,k从bug[root]到 m
        for(int j=m; j>=bug[root]; j--){    //背包容量为 j 时 
            for(int k=j-1; k>=bug[root]; k--){    //root 这颗树 k 个战士 
                //如果放第 i 棵子树,则脑量等于包括root和前面 i-1 棵子树 k 个战士获取的最大脑量加上第 i 棵子树能获取的最大脑量
                dp[root][j] = max(dp[root][j], dp[root][k] + dp[v][j-k]); 
            }
        } 
    }
}

 

posted @ 2017-07-29 17:11  淡蓝色光  阅读(134)  评论(0编辑  收藏  举报