背包三讲

来源:互联网 发布:用sql语句查询年龄在 编辑:程序博客网 时间:2024/05/21 10:11

V表示背包容量,v[i]表示物品价值,w[i]表示物品重量,c[i]表示某种物品的个数


1、01背包

for(i=0;i<n;i++)//表示物品总个数    for(j=V;j>=w[i];j--)        dp[j] = max(dp[j],dp[j-w[i]] + v[i]);


2、完全背包

for(i=0;i<n;i++)//表示物品总个数    for(j=w[i];j<=V;j++)        dp[j] = max(dp[j],dp[j-w[i]] + v[i]);


注意看的话,会发现其实01背包和完全背包只有一行是不一样的。

01背包的二维状态转移方程是dp[i][j] = max(dp[i][j],dp[i-1][j-w[i]] + v[i]),发现第i个状态是由第i-1个状态推出来的,所以第一维可以优化掉,为什么第二重循环是倒着来的呢,因为dp[j] = max(dp[j], dp[j-w[i]] + v[i]),如果正着循环,假设dp[j]由第i-1个状态推出的,那么j正着循环后会变大,那么dp[j+w[i]]就不是由第i-1个状态推出来的,就是由前面算出的第i个状态的dp[j]推出,这样就不是每一个物品只用一次了,很明显就不符合01背包的性质了。

完全背包可以正着循环的原因是完全背包是一种物品有无限多个,正着循环正好可以让一个物品用很多次,这样算出来的就是我们想要的结果。


3、多重背包

for(i=0;i<n;i++)//表示物品的种类{    if(v[i] > V)        continue;    if(v[i]*w[i]>=V)    {        for(j=v[i];j<=V;j++)            dp[j] = max(dp[j],dp[j-w[i]] + v[i]);        continue;    }    else    {        int k = 1;        while(k < c[i])        {            for(j=V;j>=w[i]*k;j--)                dp[j] = max(dp[j],dp[j-k*w[i]] + k*v[i]);            c[i] -= k;            k *= 2;        }        for(j=V;j>=w[i]*c[i];j--)            dp[j] = max(dp[j],dp[j-w[i]*c[i]] + v[i]*c[i]);    }}

下面是摘自背包九讲的多重背包的过程,看着应该比较清晰

def MultiplePack(F,C,W,M)
if C M  V
CompletePack(F,C,W)
return
k := 1
while k < M
ZeroOnePack(kC,kW)
M := M

解释一下多重背包的过程,如果一个物品的数量乘上他的重量,已经超过了背包的容量,那么就可以当成完全背包来处理;如果没有超过背包的话,可以把拆分成01背包来处理,这里用到了二进制优化,可以大大优化时间复杂度。

0 0
原创粉丝点击