HDU ACM 1011 Starship Troopers->树形背包(树上的背包)

来源:互联网 发布:linux内核编译命令 编辑:程序博客网 时间:2024/05/19 09:11
题意:n个洞组成一棵树,有m个士兵,从1号洞开始攻打,每个洞有a个bug和b的价值。一个士兵可以打20个bug,为了拿到这个洞的价值b必须留下k个士兵消灭这个洞的所有bug(k*20>=bug的数量,且留下的士兵不可以再去攻打其他的洞,且必须攻打了前面的洞才可以攻打后面的洞)。问花费这m个士兵可以得到的最大价值是多少。 

dp方程:dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[ son[i] ][ k ])。表示用j个士兵占领以i为根节点的子树所能获得的最大值。

目标状态就是dp[1][m]。

即使某个山洞的bug数量为 0,也至少需要1个士兵去获取brain,所以当手上的士兵数量为0时,可以直接输出0。

#include<iostream>#include<vector>using namespace std;#define N 105int n,m;int cost[N],weg[N];int dp[N][N];bool vis[N];              //记录访问情况vector<int>map[N];int max(int a,int b){return a>b?a:b;}void dfs(int r){int i,j,k,tmp,t;tmp=(cost[r]+19)/20;  //不足20也需要一个士兵for(i=tmp;i<=m;i++) dp[r][i]=weg[r];  //当前洞中的怪被打可以获得的价值vis[r]=true;for(i=0;i<map[r].size();i++){t=map[r][i];if(vis[t])continue;dfs(t);         //搜索子节点for(j=m;j>=tmp;j--)for(k=1;k<=j-tmp;k++) //留下tmp打rdp[r][j]=max(dp[r][j],dp[r][j-k]+dp[t][k]);}}int main(){int i,u,v;while(scanf("%d%d",&n,&m)==2 && (n!=-1 || m!=-1)){for(i=0;i<=n;i++)map[i].clear();memset(dp,0,sizeof(dp));memset(vis,0,sizeof(vis));for(i=1;i<=n;i++)scanf("%d%d",cost+i,weg+i);for(i=1;i<n;i++){scanf("%d%d",&u,&v);map[u].push_back(v);map[v].push_back(u);}if(m==0){puts("0");continue;}dfs(1);printf("%d\n",dp[1][m]);}    return 0;}


0 0
原创粉丝点击