背包问题

来源:互联网 发布:sql怎么删除置顶列 编辑:程序博客网 时间:2024/05/21 11:06

一.01背包问题

给定一个容量为W的背包。和n个物品各为wi重量和价值各为ci的物品i。(1<=i<=n)

问放哪几个物品进去使总价值最大。

顾名思义,01背包,01的0代表不放进去,1代表放进去。

对于每个物品i都有01两种选择。

如果用最原始的枚举法。

从第一个物品开始对每个物品进行枚举放还是不放。这样的算法实际上是一棵n层二叉树,所以时间复杂度为(2^n)。显然应该有更好的算法来解决。

从构造这个二叉树的过程中其实就可以发现。

每个节点其实是一个状态,每个状态含有两个关键参数CC\WW。


比如:根节点(第0层)代表任何物品都不放进去,状态参数为0\W,前者代表此时总价值0,可用背包容量为W。

第一层有两个节点,因为每次都是01二分叉,我们规定左边代表0状态,右边代表1状态。

故第一层的左节点参数值为0/W,右节点参数为c1\(W-w1)。

...

这样一直下来到第n层,我们比较第n层的所有WW>= 0的节点的CC值,选出最大的,则是我们满足题意的。

枚举的实际过程,按我的理解实际就是这么一棵树的构成。

而当你画树的过程时,其实你就会有dp的灵感,因为很多节点的状态参数是重复的,既然是重复的我们就可用dp进行“剪枝”。

说这么多其实只是我的感悟,我觉得对理解01背包dp应该有所启发。


首先我们注意到我们是一直造树造到第n层之后才开始比较输出最佳值。

其实我们可以在造出第i层之后即可求出第i层的最佳值。

这是因为第i+1层的最佳值和它的上一层即第i层的最佳值有关。

关系即是下面这个转移方程:

用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}


原创粉丝点击