动态规划之01背包详解

 

先看问题:

N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。

通过阅读问题,因为背包就是要往里面放东西,所以一件物品就是有放或不放两种情况,那么怎么才能判断当前物品该不该放进去从而使利益最大化呢。

首先,我们用i代表前i件物品,v代表包的最大承重,ci是第i件物品的重量、wi是第i件物品的价值、f[i,j]是最大价值(i个物品放入有j个空间的包)

第一种情况:第i件不放进去,这时所得价值(f[i][j]):f[i][j]=f[i-1][v]

因为不放进去,所以说当前价值(f[i][j])为前i-1个物品的价值f[i-1][v]:当前i个物品用j个空间所拥有的价值就等于前i-1个物品用j个空间的价值,因为物品i没有放进去,

所以就相当于继承f[i-1][v]了,所以f[i][j]=f[i-1][v]

另一种情况:第i件放进去,这时所得价值为:f[i][j]=f[i-1][v-c[i]]+w[i]

因为放进去了,所以说当前价值(f[i][j])不是前i-1个物品的价值f[i-1][v]:因为你放进去了,所以这个时候包内的空间就不是v了,而应该是v-c[i]所以说,

你现在需要继承前i-1个物品占用体积为v-c[i]时的价值,因为你将物品放进去了,所以还需要加上当前物品价值wi,所以f[i][j]=f[i-1][v-c[i]]+w[i]

因为对于第i件物品就是这两种操作,而你又想要最大价值,所以

f[i][j]=max(f[i-1][v],f[i-1][v-c[i]]+w[i])

贴一段代码:(n为物品数量)

?

1

2

3

4

5

6

for (int i=1;i<=n;++i) { for (int j=v;j>=0;--j)   {

       if(c[i]<=j)//如果当前物品可以放入当前空间的背包

       f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+w[i]);

       else f[i][j]=f[i-1][j];//如果当前物品放不进去,那么继承前i个物品在当前空间大小时的价值

   }

  }

n=3v=6时的表格:

c[1]=2 , w[1]=7 ;  c[2]=3 , w[2]=1 ; c[3]=5 , w[3]=4;我用红色的数字标记一下在当前代码下填表的顺序,运行之后f[n][v]为最优值,可见此时最优值为f[3][6]=8;

 

i\j

j=0

j=1

j=2

j=3

j=4

j=5

j=6

i=0

0

0

0

0

0

0

0


i=1

0

(6)7

(5)7

(4)7

(3)7

(2)7

(1)7


i=2

0

(12)8

(11)8

(10)8

(9)8

(8)8

(7)8


i=3

0

(18)0

(17)0

(16)0

(15)0

(14)8

(13)8

 

以上是用二维数组存储的,其实还可以用一维数组存储进行空间优化(滚动数组)

从上面计算f[i][j]可以看出,在计算f[i][j]时只使用了f[i-1][0……j],所以说并没有使用其他子问题,所以说在存储子问题解的时候,只用存储f[i-1]的子问题解即可;所以说可以用一个一维数组替换掉那个二维数组,一个存储子问题,一个存储正在解决的子问题。

我们用f[v]表示当前状态是容量为v的背包所得价值

那滚动数组应当如何滚动呢,用二维数组计算f[i][j]时只使用了f[i-1][0……j],而并没有使用到f[i-1][j+1],所以在计算j的循环的时候,j=M……1

这个时候你也许会问,那你上面用的二维数组不也是逆序吗,其实对于二维数组的来说,正逆序无所谓,当你懂得01背包的算法之后就可以明白这一点

下面给出一维数组优化过的代码:

?

1

2

3

4

5

6

7

8

9

for (int i=1;i<=n;++i)

{

        for (int j=v;j>=0;--j)

    {

            if(t[i]<=j)

            f[j]=max(f[j],f[j-c[i]]+c[i]);

            else f[j]=f[j];

     }

}

  因为二维的我已经讲解的很详细了,所以一维数组的跟二维数组的相差的不是太多,只要你懂了二维数组的那个是如何工作的,这个我相信你也会很容易理解,我这里就不细化讲解了。

本文章原创,未经我允许不得转载

Authentic Author : Tranx

原网页

2017.10.1  21:11

分类: 动态规划(DP)

https://www.cnblogs.com/Kalix/p/7622102.htm

完全背包详解l完全背包详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值