Problem Description You, the leader of Starship Troopers, are sent to destroy a base of the bugs. The base is built underground. It is actually a huge cavern, which consists of many rooms connected with tunnels. Each room is occupied by some bugs, and their brains hide in some of the rooms. Scientists have just developed a new weapon and want to experiment it on some brains. Your task is to destroy the whole base, and capture as many brains as possible.
Input The input contains several test cases. The first line of each test case contains two integers N (0 < N <= 100) and M (0 <= M <= 100), which are the number of rooms in the cavern and the number of starship troopers you have, respectively. The following N lines give the description of the rooms. Each line contains two non-negative integers -- the amount of bugs inside and the possibility of containing a brain, respectively. The next N - 1 lines give the description of tunnels. Each tunnel is described by two integers, which are the indices of the two rooms it connects. Rooms are numbered from 1 and room 1 is the entrance to the cavern.
Output For each test case, print on a single line the maximum sum of all the possibilities of containing brains for the taken rooms.
Sample Input 5 10 50 10 40 10 40 20 65 30 70 30 1 2 1 3 2 4 2 5 1 1 20 7 -1 -1
Sample Output 50 7 |
开始看了半天都没看懂题意,为自己的英语感到绝望。
题意:在n个洞中(树结构),每个洞有a个"bugs"和b的价值。你有m个士兵,从1号房间开始攻打,一个士兵可以打最多20个"bugs",如果要拿到某个洞的价值,需留下k个士兵消灭这个洞的所有"bugs",问你花费这m个士兵可以得到的最大价值是多少?
注意的是:必须攻打了前面的洞才能接着打后面的洞。
思路:不难想象这是背包问题,其次是在树形结构上,所以是道正正经经的树形DP问题。
转移方程:dp[p][j]=max(dp[p][j],dp[p][j-k]+dp[ son[p] ][ k ]);
具体实现参考代码备注。
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<set>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<stack>
#include<map>
#define N 110
#define LL long long int
using namespace std;
const LL MOD=1e19;
int w[N],c[N];
vector<int> ed[N];
bool vis[N];
int dp[N][N];//dp[i][j]表示第i个洞消耗j个士兵的获得值
int n,m;
void dfs(int x){
vis[x]=true;
int temp=(c[x]+19)/20;//第x个洞要消耗的士兵数量
for(int i=temp;i<=m;i++)
dp[x][i]=w[x];
for(int i=0;i<ed[x].size();i++){
int to=ed[x][i];
if(vis[to]==true)
continue;
dfs(to);
//从叶子节点开始进行dp
for(int j=m;j>=temp;j--){
for(int k=1;k<=j-temp;k++)//当前洞是否派出temp个士兵
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[to][k]);
}
}
}
int main(){
ios_base::sync_with_stdio(false);
int a,b;
while(cin>>n>>m){
if(n==-1||m==-1)
break;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
cin>>a>>b;
w[i]=b;
c[i]=a;
ed[i].clear();
vis[i]=false;
}
for(int i=0;i<n-1;i++){
cin>>a>>b;
ed[a].push_back(b);
ed[b].push_back(a);
}
if(m==0){
cout<<"0"<<endl;
continue;
}
dfs(1);
cout<<dp[1][m]<<endl;
}
}