题目大意:给一棵有根带点权树,并且给出容量。求在不超过容量下的最大权值。前提是选完父节点才能选子节点。
题目分析:树上的分组背包。
ps:特判m为0时的情况。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int N=105; const int INF=1000000000; int n,m; int bug[N]; int w[N]; int dp[N][N]; vector<int>e[N]; void init() { memset(dp,0,sizeof(dp)); for(int i=1;i<=n;++i){ scanf("%d%d",bug+i,w+i); e[i].clear(); } int a,b; for(int i=1;i<n;++i){ scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } } int getTroopers(int x) { return (x+19)/20; } int dfs(int u,int fa) { int x=getTroopers(bug[u]); for(int i=x;i<=m;++i) dp[u][i]=w[u]; for(int i=0;i<e[u].size();++i){ int v=e[u][i]; if(v==fa) continue; dfs(v,u); for(int j=m;j>=x;--j){ for(int k=1;k<=j-x;++k){ dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]); } } } } void solve() { if(m==0) printf("0 "); else{ dfs(1,-1); printf("%d ",dp[1][m]); } } int main() { while(~scanf("%d%d",&n,&m)&&(n!=-1||m!=-1)) { init(); solve(); } return 0; }