至多与恰好
如果问恰好装(v),则初始化(dp[]=-INF,dp[0]=0)。二维(dp)则初始化(dp[][]=-INF,dp[0][0]=0)。(这样就能是那些能够恰好装满背包的物品的值为正数,而那些不能恰好装满背包的物品的值就为负数。)
如果问至多装(v),则初始化(dp[]=0)。
一定要注意,要求恰好时,分组背包枚举某一组的元素之前,要再设(dp[j]=-INF)。((INF)的值要够小!)
二维(dp)时(要求恰好),最开始的(max)也可能要设(-INF)(除了第一次时)
01背包和完全背包枚举顺序
01背包是倒序,完全背包是顺序。
(若倒序枚举,(j)只会一直减小,所以我们总是用第(i-1)个阶段向第(i)个阶段转移,是01背包。如果是正序,那么(j)有可能被(j-v_i)更新。(j)增大到(j+v_i)时,又可能被(j)更新。这时两个都处于第(i)个阶段的状态之间发生了转移,相当于第(i)个物品被使用了两次,是完全背包。)
分组背包枚举顺序
先枚举是哪个组(i),再倒序枚举体积(j),最后再枚举每组组内元素(k)。
(注意枚举顺序。(i)是阶段,(i)与(j)共同构成状态,而(k)是决策。)
多重背包枚举顺序
思想:转化为共有(sumlimits_{i=1}^{n}k_i)个物品的01背包问题((k_i)是每种物品的个数)。
先枚举是哪种物品(i),再枚举(i)的个数(j),最后再倒序枚举体积(k),做01背包dp[k]=max(dp[k],dp[k-w[i]]+c[i])
。
注意res=max{dp[0~v]}
二进制拆分法(优化多重背包)
原来的多重背包时间复杂度是(O(Vsumlimits_{i=1}^nk_i))的,效率较低。
我们可以把数量为(k_i)的第(i)种物品拆成(p+2)个物品((p)是满足(2^0+2^1+2^2+...+2^ple{k_i})的最大整数)。
它们的体积分别为(2^0*w_i,2^1*w_i,...,2^p*w_i,r_i*w_i)((r_i=k_i-sumlimits_{i=0}^p2^i))。
那么这(p+2)个物品可以且只能凑成(0sim{k_i}*w_i)之间所有能被(k_i)整除的数,这等价于原问题中体积为(w_i)的物品可以使用(0sim{k_i})次。这时的复杂度是(O(Vsumlimits_{i=1}^nlog(k_i)))。