题目链接:https://www.luogu.org/problemnew/show/P3360
题解:
首先我们把边上的消耗放到向下的点上,如果是叶子节点的话就先做一次0/1背包
发现这是一颗二叉树,转移的时候枚举给左儿子多少时间,右儿子多少时间就好
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> typedef long long ll; using std::max; const int N=1000+15; ll n,tot=1; ll dp[N][N],w[N],c[N]; inline ll read() { char ch=getchar(); ll s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } void dfs(int now) { ll t=read(),x=read(); t<<=1; if (x) { for (ll i=1;i<=x;i++) w[i]=read(),c[i]=read(); for (ll i=1;i<=x;i++) { for (ll j=n;j>=c[i];j--) if (j-c[i]>=t) dp[now][j]=max(dp[now][j],dp[now][j-c[i]]+w[i]); } return; } ll l=++tot;dfs(tot); ll r=++tot;dfs(tot); for (ll i=t;i<=n;i++) for (ll j=0;j<=i-t;j++) { dp[now][i]=max(dp[now][i],dp[l][j]+dp[r][i-t-j]); } } int main() { n=read();n--; dfs(1); printf("%lld ",dp[1][n]); return 0; }