动态规划--二进制背包/多重背包

之前有过一篇多重背包判断是否能凑一个整数的问题->传送门
如果我们不是判断是否能凑成这个数,而是计算这个数内的背包最大值,就不能用这个写法了(也可能是我太菜了,一直WA)

于是就有了二进制背包的方式

在多重背包中如果每个背包被选择的次数maxi都比较小
我们可以把他拆违maxi个相同的背包
但如果maxi可能比较大,那么最后的背包总数就可能会超时
怎么把这个maxi用一些更小的数字来组合而成呢?

我们都知道,任意一个正整数都能被表示为二进制之和,而2的0次方即1可以表示任意一个数,所以如果在多重背包问题中我们知道每个背包能选择的最大次数maxi,我们就可以把maxi分解为二进制,把其中某些二进制数加起来就能得到小于等于maxi的任意一个数。

如果没有理解,我们就看这个例子
example:
我们有个背包最多能被选择40次,也就是我们可以选择0到40次这个背包,而40=1+2+4+8+16+9,1、2、4、8、16、9这几个数就可以构成1到40中的任意一个数,我们如果不选择这个背包就是0。(!!!注意:一定是从2的0次方开始递增分解)
P1833

#include <bits/stdc++.h>
using namespace std;
int ans[1005];//all可能会很多,所以不能用二维的背包
int t[10005];
int score[10005];
int c[10005];
int a[1000005];
int b[1000005];
int all=0;
int n;
void transf()//转化背包
{
    for(int i=1;i<=n;i++)
    {
        int tr=1;
        while(c[i])
        {
            a[++all]=tr*t[i];
            b[all]=tr*score[i];
            c[i]-=tr;
            tr*=2;
            if(c[i]<=tr)
            {
                a[++all]=c[i]*t[i];
                b[all]=c[i]*score[i];
                break;
            }
        }
    }
}
int main()
{
    int h1,m1,h2,m2;
    scanf("%d %*c%d%d%*c%d",&h1,&m1,&h2,&m2);
    cin >> n;
    for(int i=1;i<=n;i++)
    {
        cin >> t[i] >> score[i] >> c[i];
        if(!c[i])
            c[i]=100000;
    }
    transf();
    if(h2<h1)
        h2+=24;
    int T=(h2*60+m2)-(h1*60+m1);
    for(int i=1;i<=all;i++)
    {
        for(int j=T;j>=a[i];j--)
        {
            ans[j]=max(ans[j],ans[j-a[i]]+b[i]);
        }
    }
    cout << ans[T] << endl ;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值