hdu1011(树形dp+背包)

src:http://acm.hdu.edu.cn/showproblem.php?pid=1011

dp[u][i]表示在结点u,消耗i军队获得的最大值。注意建树时用双向边,因为结点1不一定是树根!!!

注意m==0时特判,这个必需要,有代价为0的房间,M=0则无法获得,样例为2 0  0 20 0 10 1 2 !!!

ac代码:

#include <iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<functional>
#include<utility>
#include<string>
#include<string.h>
#include<vector>
#include<iomanip>
#include<stack>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
const int inf=99999999;

int n,m,dp[101][101],b[101],g[101];
bool vis[101];
vector<int>head[101];
void init()
{
    memset(dp,0,sizeof(dp));
    memset(vis,false,sizeof(vis));
    FOR(i,1,n)head[i].clear();
}
void add_edge(int beg,int ed){head[beg].push_back(ed);}
void dfs(int u)
{
    vis[u]=true;
    for(int i=b[u];i<=m;i++)dp[u][i]=g[u];
    for(int i=0;i<head[u].size();i++){
        int v=head[u][i];
        if(vis[v]==true)continue;
        dfs(v);
        for(int j=m;j>=b[u];j--)for(int k=1;k<=j-b[u];k++){
            Max(dp[u][j],dp[u][j-k]+dp[v][k]);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>m&&n!=-1&&m!=-1){
        int beg,ed;
        init();
        for(int i=1;i<=n;i++){cin>>b[i]>>g[i];}
        for(int i=1;i<=n;i++)b[i]=(b[i]+19)/20;
        for(int i=1;i<n;i++){cin>>beg>>ed;add_edge(beg,ed);add_edge(ed,beg);}
        if(!m){   //注意m==0时特判
            cout<<"0"<<endl;continue;
        }
        dfs(1);
        cout<<dp[1][m]<<endl;
    }
    return 0;
}

 

posted @ 2018-05-16 22:10  WindFreedom  阅读(466)  评论(0)    收藏  举报