CodeForces - 815C Karen and Supermarket
Posted on 2022-11-14 21:39 Capterlliar 阅读(21) 评论(0) 编辑 收藏 举报前置:树上背包
问题描述:给出一组物品,每个物品有体积v和价值w,其依赖关系形成一棵树,选择一个子节点就要选择其所有祖先节点。给定背包容量,求最大价值。
原始做法:设dp[i][j]为以物品i为子树根结点,在子树内选择j个物品的最大价值。转移:
dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[child][k]);
优化:树上背包的上下界优化
题意:给出一组商品,每件商品原价c[i],有优惠券可降价d[i]元。优惠券之间有依赖关系,形成一棵树。现在你有b元,求最多买几件商品。
解:设dp[i][j][0/1]为以物品i为子树根结点,在子树内选择j个物品,且物品i用/不用优惠券最多买几个物品。转移方程比较显然,当前不用优惠券所有子节点肯定也不能用优惠券。但不选当前结点可以选子节点,所以转移枚举k的时候可以让j=k。
代码:
#include <bits/stdc++.h> using namespace std; #define maxx 5005 #define maxn 25 #define maxm 205 #define ll long long #define inf 1000000009 #define mod 2520 struct edge{ int u,v,w,next; }e[maxx*2]; int head[maxx]={0},cnt=0; void add(int u,int v){ e[++cnt].u=u;e[cnt].v=v;e[cnt].next=head[u];head[u]=cnt; } ll n,b; ll c[maxx]={0},d[maxx]={0}; ll son[maxx]={0}; ll dp[maxx][maxx][2]={0}; void dfs1(int now){ dp[now][0][0]=0; dp[now][1][0]=c[now]; dp[now][1][1]=d[now]; son[now]=1; for(int i=head[now];i;i=e[i].next){ int to=e[i].v; dfs1(to); for(int j=min(n,son[now]+son[to]);j>=1;j--){ for(int k=max(1ll,j-son[now]);k<=son[to]&&k<=j;k++){ //dp[now][j]=max(dp[now][j],dp[now][j-k]+dp[to][k]); dp[now][j][0]=min(dp[now][j][0],dp[now][j-k][0]+dp[to][k][0]); dp[now][j][1]=min(dp[now][j][1],dp[now][j-k][1]+dp[to][k][0]); dp[now][j][1]=min(dp[now][j][1],dp[now][j-k][1]+dp[to][k][1]); } } son[now]+=son[to]; } } signed main() { scanf("%lld%lld",&n,&b); scanf("%lld%lld",&c[1],&d[1]); for(int i=2;i<=n;i++){ ll x; scanf("%lld%lld%lld",&c[i],&d[i],&x); add(x,i); } for(int i=1;i<=n;i++){ d[i]=c[i]-d[i]; } memset(dp,0x3f3f3f3f,sizeof dp); dfs1(1); ll ans=0; for(int i=0;i<=n;i++){ if(dp[1][i][0]<=b||dp[1][i][1]<=b){ ans=i; } } printf("%lld\n",ans); return 0; } //dp[i][j][k] to node i, choose j goods, using or not the discount
真っ白な世界で目を覚ませば 在全白的世界中醒来
伸ばす腕は何もつかめない 伸出手却什么也掌握不到
见上げた空が近くなるほどに 仰望天空,似乎有变近的感觉
仆は何を失った? 我失去了什么吗?
透通る波 澄澈纯粹的波纹
映る仆らの影は苍く远く 映照出的我们的影子是那么苍蓝那么遥远
あの日仆は世界を知り 那一天我明白了什么是世界—— 歌に形はないけれど(虽然歌声无形)