一个容量为m的背包,a个重量为 w [ i ] ,价值为 v [ i ] ,数量为 s [ i ] 的物品,求解最大价值方案。

 

(千万别想:每次 s [ i ] - 1 。这是对于动态规划的错误理解。)

 

/******************************************************************************************************************************************************************************************/

多重背包问题:

这种问题其实是01背包的变形:对于第 i 种物品,可以装 j 个( 0 ≤ j ≤ s [ i ] )

for(int i=0;i<a;i++)
        for(int j=m;j>=w[i];j--)
            for(int k=1;k*w[i]<=j&&k<=s[i];k++)
                dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);

时间复杂度为o(m*∑s)

 

/********************************************************************************************************************************************************************************************/

 

多重背包的二进制优化:

朴素的循环中,对于每一种物品,第三层循环大大增加了时间复杂度。

注意到这样一件事情:任意正整数 n ,从1到 n 这 n 个数可以被 1 , 2 , 4 , 8 , ... , 2 ^ (k-1) , n - (2 ^ k) + 1 (2 ^ (k+1) > n)这 k + 1 个数(即log(n)+1个数)加和得到。

所以,对于每一个原始的物品 i ,可以构建一个新的物品队列 L,在对L进行01背包的时候,就已经将对i的多重背包考虑完毕。L中的每一项与i有一个系数关系,就是上述那 k + 1 个数。这就是用二进制思想进行了优化。复杂度大大降低。

for(int i=0;i<l;i++)       //l为新构建的物品总数 
        for(int j=m;j>=weight[i];j--)     //weight和value中已经对应的乘好了系数 
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);

时间复杂度为o(m*log(∑s))  (?)