【多重背包的优化】

牛逼的是运用二进制的思想来这样拆分,就可以简化for循环的复杂度,又可以达到for单个循环的效果。

所以直接记模板:

 for(int i=1;i<=种类数;i++)
    {
        int k=1;     //对于每一种,k准备取1 2 4 8...
        int temp=m[i];  //m[i]为第i种的数量
        for(k; k<=temp ; k*=2)
        {
            value[++num]=k*v[i];  //v[i]为第i种的每个的价值
            temp-=k;
        }
        if(temp>0)
            value[++num]=temp*v[i];  
    }

这样就可以得到所有种类任意价值数的组合。

多重背包其实就是这样的,先把value数组给弄好了,然后再把value数组的元素每一个都看成一个单独的背包,对这些背包来做01背包的操作即可。



#include<iostream>
#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6;
    long long value[maxn];
const int maxnn=1e6;
    long long dp[maxnn];

int main()
{
    int m[7];
    for(int i=1;i<=6;i++)
        cin>>m[i];  //输入每种娃娃有多少个
    int num=-1;
    for(int i=1;i<=6;i++)
    {
        int k=1;
        int temp=m[i];
        for(k; k<=temp ; k*=2)
        {
            value[++num]=k*i;  //都拆分
            temp-=k;
        }
        if(temp>0)
            value[++num]=temp*i;
    }
    

    long long allsum=0;
    for(int i=1;i<=6;i++)
    {
        allsum+=i*m[i];
    }
    if (allsum%2!=0)
    {
        cout<<"Can't be divided.";
        return 0;
    }
    long long half=allsum/2;
    for(int i=0;i<=num;i++)
    {
        for(long long j=half;j>=value[i];j--)
        {
            dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
        }
    }
    
    if(dp[half]==half)
        cout<<"Can be divided.";
    else
        cout<<"Can't be divided.";
    return 0;
}

代码中加粗部分是第二个我新领会到的知识点(用我的话来阐述):

其实当一个dp数组,下标和它的数值代表的是同一个东西A时,结合max函数来做dp,最后,去判断dp[num]==num其实也就是在判断:当我想要num个A时,我究竟能不能得到num个A。若相等,则能。


另外,此题之前有想过拆分之后用“二进制枚举”的方法来组合,无法AC,发现:二进制枚举存在一个是数位不够(i弄成long long 也不行),一个是时间复杂度过高(num * 2^num)的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值