题意:给你一颗树,每个树都有一个花费值,一个获得值,然后给你m个人,一个人可以相当于20个bug,不满足20个也需要花费一个,最后问你最大可以获得多少价值
思路:枚举现在的结点x的所有儿子,dp[i][j]代表结点i现在有j个人,dp[i][j]当然转移的是最大值,所以对于结点x,dp[x][j+k]=dp[x][j]+dp[son][k];因为是自下而上的进行dp,所以对于dp[x][j]的价值,在其他子结点的时候已经处理过了,就是01背包的思想(我觉得不是很容易理解,还是01背包学的太烂了),相当于暴力的枚举了每次的划分
代码:
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <vector> #include <string> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #define zero(a) fabs(a)<eps #define lowbit(x) (x&(-x)) #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define MOD 1000000007 int max(int x,int y){return x>y?x:y;}; int min(int x,int y){return x<y?x:y;}; int max(int x,int y,int z){return max(x,max(y,z));}; int min(int x,int y,int z){return min(x,min(y,z));}; typedef long long LL; const double PI=acos(-1.0); const double eps=1e-8; const int inf=0x3f3f3f3f; const LL linf=0x3f3f3f3f3f3f3f3fLL; using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=100+7; int n,m; vector<int>mp[maxn]; int a[maxn],val[maxn]; int dp[maxn][maxn]; bool vis[maxn]; void dfs(int rt) { vis[rt]=true; for(int j=a[rt];j<=m;j++){ dp[rt][j]=val[rt]; } for(int i=0;i<mp[rt].size();i++){ int now=mp[rt][i]; if(vis[now])continue; dfs(now); for(int j=m;j>=a[rt];j--){ for(int k=1;j+k<=m;k++){ if(dp[now][k]) dp[rt][j+k]=max(dp[rt][j+k],dp[rt][j]+dp[now][k]); } } } } int main() { while(~scanf("%d%d",&n,&m)){ if(n==-1&&m==-1)break; for(int i=0;i<=n;i++)mp[i].clear(); memset(dp,0,sizeof(dp)); memset(vis,false,sizeof(vis)); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i],&val[i]); a[i]=(a[i]+19)/20; } for(int i=0;i<n-1;i++){ int t1,t2; scanf("%d%d",&t1,&t2); mp[t1].push_back(t2); mp[t2].push_back(t1); } if(m==0){ puts("0"); continue; } dfs(1); printf("%d ",dp[1][m]); } return 0; }