博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
01背包问题
阅读量:6641 次
发布时间:2019-06-25

本文共 2527 字,大约阅读时间需要 8 分钟。

01背包问题

一:问题

  有$N$件物品和一个容量为$V$的背包。第$i$件物品的体积是$C_i$,其价值是$W_i$。求解,在不超过背包容量情况下,将哪些物品装入背包可使价值总和最大。

二:基本思路

  这是最基础的背包问题,特点是:每种物品仅有一件。

  状态 $F[i,v]$表示前$i$件物品中选择若干件放在容量为$v$的背包中,可以取得的最大价值。
  转移方程
$$
F[i,v]=\max {F[i−1,v],F[i−1,v−C_i]+W_i}
$$
对于第$i$件物品,有放与不放两种选择。若选择不放,$F[i,v]=F[i−1,v]$;若选择放,$v−C_i$确保有足够的空间,随之$F[i,v]=F[i−1,v−C_i]+W_i$。

三:代码

/** * * author 刘毅(Limer) * date   2017-03-17 * mode   C++ */#include
#include
using namespace std;int main(){ const int N = 6; //物品个数 const int V = 10; //背包体积 int C[N + 1] = { -1,5,6,5,1,19,7 }; //第i个物品的体积(下标从1开始) int W[N + 1] = { -1,2,3,1,4,6,5 }; //第i个物品的价值 int F[N + 1][V + 1] = { 0 }; //状态 for (int i = 1; i <= N; i++) //对于第i个物品 for (int v = 0; v <= V; v++) { F[i][v] = F[i - 1][v]; //第i个不放 if (v - C[i] >= 0 && F[i][v] < F[i - 1][v - C[i]] + W[i]) //如果比它大,再放第i个 F[i][v] = F[i - 1][v - C[i]] + W[i]; } cout << "最大价值是:" << F[N][V] << endl; //9 return 0;}

四:空间复杂度优化

  以上方法的时间和空间复杂度均为$O(VN)$,其中时间复杂度应该已经不能再优化了,但空间复杂度却可以优化到$O(V)$。

  先考虑上面讲的基本思路如何实现,肯定是有一个主循环i ← 1 to N,每次算出来二维数组$F[i,v]$的所有值。那么,如果只用一个数组$F[v]$能不能保证第$i$次循环结束后$F[v]$中表示的就是我们定义的状态$F[i,v]$呢?
  $F[i,v]$是由$F[i−1,v]$和$F[i−1,v−C_i]$两个子问题递推而来,能否保证在推$F[i,v]$时(也即在第$i$次主循环中推$F[v]$时)能够取用$F[i−1,v]$和$F[i−1,v−C_i]$的值呢?
  事实上,这要求在每次主循环中我们以v ← V to C[i]的递减顺序计算$F[v]$,这样才能保证计算$F[v]$时$F[v−C_i]$保存的是状态$F[i−1,v−C_i]$的值。
  优化后的代码如下:

/** * * author 刘毅(Limer) * date   2017-03-17 * mode   C++ */#include
#include
using namespace std;int main(){ const int N = 6; //物品个数 const int V = 10; //背包体积 int C[N + 1] = { -1,5,6,5,1,19,7 }; //第i个物品的体积(下标从1开始) int W[N + 1] = { -1,2,3,1,4,6,5 }; //第i个物品的价值 int F[V + 1] = { 0 }; //状态 for (int i = 1; i <= N; i++) //对于第i个物品 for (int v = V; v >= C[i]; v--) F[v] = max(F[v], F[v - C[i]] + W[i]); cout << "最大价值是:" << F[V] << endl; //9 return 0;}

五:初始化的细节问题

  我们看到的求最优解的背包问题题目中,事实上有两种不太相同的问法。有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。这两种问法的实现方法只是在初始化的时候有所不同。

  如果是第一种问法,要求恰好装满背包,那么在初始化时除了F[0]为0,其它F[1]...F[V]均设为−∞,这样就可以保证最终得到的F[V]是一种恰好装满背包的最优解。如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将F[0]...F[V]全部设为0。
  这是为什么呢?可以这样理解:初始化的F数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可以在什么也不装且价值为0的情况下被“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,应该被赋值为-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。

参考文献:

[ 1 ] .背包九讲.

文章转自我的个人博客:

转载地址:http://poovo.baihongyu.com/

你可能感兴趣的文章
vue2 遇到的问题汇集ing
查看>>
反射的具体应用
查看>>
长安CS35
查看>>
android 数据库的增删改查的另一种方式
查看>>
什么是优先级队列(priority queue)?
查看>>
As3 Embed Swf
查看>>
郭建龙:“阿里云”是如何失控的
查看>>
JMeter PerfMon Metrics Collector性能监控插件
查看>>
如何取得linux下进程的一些核心信息
查看>>
【windows开发实现记事本程序——界面篇】
查看>>
前端开发规范-javascript规范
查看>>
java中的问号与冒号? : 表达式
查看>>
统计一个数组中正数和负数的个数
查看>>
vagrant up下载box慢的解决办法
查看>>
python中if.while.for循环使用
查看>>
Foundation框架-NSTimeZone
查看>>
初始MyBatis
查看>>
Xcode8 问题
查看>>
java中获取文件目录
查看>>
echarts+php+mysql 绘图实例
查看>>