菜鸟都能理解的01背包问题(空间如何优化)
2013-04-07 16:48
288 查看
http://www.2cto.com/kf/201301/184347.html
如果你不知道什么叫做0-1背包问题,下面是0-1背包问题的简单描述
假设有n件物品
每件物品的体积为w1, w2……wn
相对应的价值为 v1, v2.……vn。
01背包是在n件物品取出若干件放在空间为total_weight的背包里,使得背包的总体积最大
关于0-1背包问题没有优化版本,请看这里
上面的核心代码是下面这一段
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= total_weight; j++) {
if (w[i] > j) {
c[i][j] = c[i-1][j];
} else {
if (c[i-1][j] > v[i]+c[i-1][j-w[i]]) {
c[i][j] = c[i-1][j];
}
else {
c[i][j] = v[i] + c[i-1][j-w[i]];
}
}
}
}
注意到状态转移方程 c[i][j] = max{c[i-1][j], c[i-1][j-w[i]]+v[i]}
每一次c[i][j]改变的值只与c[i-1][x] {x:1...j}有关c[i-1][x]是前一次i循环保存下来的值,因此,可以将c缩减成一维数组
状态转移方程转换为 c[j] = max(c[j], c[j-w[i]]+v[i]);
并且,我们注意到状态转移方程,每一次推导c[i][j]是通过c[i-1][j-w[i]]来推导的,而不是通过c[i][j-w[i]]
因此,j的扫描顺序应该改成从大到小
否则,第i次求c数组,必然先求的c[j-w[i]]的值(即c[i][j-w[i]]),再求c[j](即c[i][j])的值
由于j递增,那么状态方程就成为下面这个样子了
c[i][j] = max(c[i-1][j], c[i][j-w[i]]+v[i])显然不符合题意
所以,上面的代码变为
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = total_weight; j >= 1; j--) {
if (w[i] > j) {
c[j] = c[j]; //表示第i次与第i-1次相等,这里因为c[j]本来就保存这上一次的值,所以这里不需变化
} else {
//说明第i件物品的重量小于背包的重量,所以可以选择第i件物品放还是不放
if (c[j] > v[i]+c[j-w[i]]) {
c[j] = c[j];
}
else {
c[j] = v[i] + c[j-w[i]];
}
}
}
}
最后我们可以做下优化,把不必要的语句去掉即可完成优化
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = total_weight; j >= w[i]; j--) {
if (c[j] <= v[i] + c[j-w[i]])
c[j] = v[i] + c[j-w[i]];
}
}
如此优美的代码简直无法想象!
注意,空间优化版本最后是求解不出来最优解序列的,但是能求出最优解,也就是最大价值
如果你不知道什么叫做0-1背包问题,下面是0-1背包问题的简单描述
假设有n件物品
每件物品的体积为w1, w2……wn
相对应的价值为 v1, v2.……vn。
01背包是在n件物品取出若干件放在空间为total_weight的背包里,使得背包的总体积最大
关于0-1背包问题没有优化版本,请看这里
上面的核心代码是下面这一段
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= total_weight; j++) {
if (w[i] > j) {
c[i][j] = c[i-1][j];
} else {
if (c[i-1][j] > v[i]+c[i-1][j-w[i]]) {
c[i][j] = c[i-1][j];
}
else {
c[i][j] = v[i] + c[i-1][j-w[i]];
}
}
}
}
注意到状态转移方程 c[i][j] = max{c[i-1][j], c[i-1][j-w[i]]+v[i]}
每一次c[i][j]改变的值只与c[i-1][x] {x:1...j}有关c[i-1][x]是前一次i循环保存下来的值,因此,可以将c缩减成一维数组
状态转移方程转换为 c[j] = max(c[j], c[j-w[i]]+v[i]);
并且,我们注意到状态转移方程,每一次推导c[i][j]是通过c[i-1][j-w[i]]来推导的,而不是通过c[i][j-w[i]]
因此,j的扫描顺序应该改成从大到小
否则,第i次求c数组,必然先求的c[j-w[i]]的值(即c[i][j-w[i]]),再求c[j](即c[i][j])的值
由于j递增,那么状态方程就成为下面这个样子了
c[i][j] = max(c[i-1][j], c[i][j-w[i]]+v[i])显然不符合题意
所以,上面的代码变为
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = total_weight; j >= 1; j--) {
if (w[i] > j) {
c[j] = c[j]; //表示第i次与第i-1次相等,这里因为c[j]本来就保存这上一次的值,所以这里不需变化
} else {
//说明第i件物品的重量小于背包的重量,所以可以选择第i件物品放还是不放
if (c[j] > v[i]+c[j-w[i]]) {
c[j] = c[j];
}
else {
c[j] = v[i] + c[j-w[i]];
}
}
}
}
最后我们可以做下优化,把不必要的语句去掉即可完成优化
[cpp]
for (int i = 1; i <= n; i++) {
for (int j = total_weight; j >= w[i]; j--) {
if (c[j] <= v[i] + c[j-w[i]])
c[j] = v[i] + c[j-w[i]];
}
}
如此优美的代码简直无法想象!
注意,空间优化版本最后是求解不出来最优解序列的,但是能求出最优解,也就是最大价值
相关文章推荐
- 菜鸟都能理解的0-1背包问题的空间优化
- 关于01背包空间优化的理解
- C#.NET常见问题(FAQ)-命名空间namespace如何理解
- 01背包问题空间优化
- 借用杭电饭卡问题来浅析 01背包问题空间复杂度的优化
- 动态规划初步-01背包问题&&一维数组(空间复杂度优化)
- 01背包问题一维空间优化的理解
- 0/1背包问题 - 如何理解 解空间
- 问题解决-某些项目因位于工作空间目录中而被隐藏 & 如何解决java项目导入出错:与另一项目重叠
- Oracle菜鸟之如何创建和删除表空间
- 请问如何解决WORD转HTML是出现的“内存或磁盘空间不足,无法显示或打印图片”这个问题?
- ASP.NET如何进行性能优化问题1
- 如何理解Android程序运行性能优化
- 如何处理Oracle中TEMP表空间满的问题
- 菜鸟如何快速理解实现通讯录——静态方法
- [01背包]NOIP 2005 PJ T3 采药 + 01背包的空间优化
- 总结概括对于大数据、高并发的网站如何进行优化的问题
- 二维费用背包问题+空间优化(滚动数组)
- 频繁分配释放内存导致的性能问题的分析 --(附)malloc分配原理浅析 mmap关注焦点 如何优化分配内存
- SQL性能优化:如何定位网络性能问题