Codeforces 1458B/1459D Glass Half Spilled 背包

文章目录


问了博哥得知这是一道背包非常震惊.然而还是不会做,看题解研究了两个小时.

题意

有很多杯子,每个杯子有容量 a a a以及当前装的水 b b b.每次可以将一个杯子里的水倒入另一个杯子,但是有 50 % 50\% 50%的损耗,并且杯子里的水不能超过其容量,否则也将损耗.询问将水全部存储至 k k k个杯子里面的时候能够存储的最大水量,输出 k k k 1 1 1取到 n n n时的答案,每个询问相互独立.

题解

d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示前 i i i个杯子中取 j j j个并且能够存储的总水量为 k k k时的最大答案.
假设我们选的杯子总容量为 A A A,总水量为 B B B,剩下的杯子还能倒出 ( S − B ) 2 \frac{(S-B)}{2} 2(SB)的水,从而我们能够得到的答案即为 m i n ( A , S + B 2 ) min(A,\frac{S+B}{2}) min(A,2S+B).
因此转移方程为 d p [ i ] [ k ] [ A ] = max ⁡ ( d p [ i − 1 ] [ k ] [ A ] , d p [ i − 1 ] [ k − 1 ] [ A − a [ i ] ] + b [ i ] ) dp[i][k][A] = \max(dp[i - 1][k][A], dp[i - 1][k - 1][A - a[i]] + b[i]) dp[i][k][A]=max(dp[i1][k][A],dp[i1][k1][Aa[i]]+b[i]).
取最大答案的时候 a n s [ k ] = min ⁡ ( A , d p [ n ] [ k ] [ A ] / 2 + B / 2 ) ) ans[k] = \min(A, dp[n][k][A] / 2 + B / 2)) ans[k]=min(A,dp[n][k][A]/2+B/2)).
代码如下.
d p dp dp数组采用滚动数组可以减少一维.

const int _=105;
int dp[_][_*_],a[_],b[_];
 
int main() {
  int i,n,s=0,j,k;
  read(n);
  memset(dp,0xcf,sizeof dp),**dp=0;
  for (i=1;i<=n;++i) read(a[i]),read(b[i]);
  for (i=1;i<=n;++i) {
    for (s+=b[i],j=i;j;--j) {
      for (k=10000;k>=a[i];--k)
        dp[j][k]=max(dp[j][k],dp[j-1][k-a[i]]+b[i]);
    }
  }
  for (i=1;i<=n;++i) {
    int lxy=0;
    for (j=0;j<=10000;++j) 
      lxy=max(lxy,min(j*2,dp[i][j]+s));
    printf("%.9lf ",lxy/2.0);
  }
}

谢谢大家.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值