在上完这节算法课后,觉得自己应该写一份关于0-1背包问题的见解,(才疏学浅)如果有原理、代码问题请及时告知,谢谢大家。
目录
一·首先0-1背包是什么?
所谓的0-1背包,我个人的见解是:有n个物品,各自都有自己的重量和价值,有一个容量为c的背包,问:如何让背包里装入的物品具有最大的价值总和?
二.什么是动态规划?
动态规划其实是大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
三.核心思路
(1)首先依据题目要求确定一个状态变量:f[i][j]表示第i件物品放入容量为j的背包的最大价值
(2)此问题的特点是第i个物品我们到底是放还是不放?
(3)如果j<w[i],表示背包的容量不够,此时放入背包物品的最大价值:f[i][j]=f[i-1][j] /*即当容量=j时,第i个放不下了,只能放前i-1个物品的最大价值*/
(4)如果j>=w[i],表示背包的容量还没有被占满,此时考虑一个问题,即上面提到过的(2)我们到底是能不能第i个物品呢?
<1>不能放,则和(3)一样,只放前i-1个物品,此时最大价值为:f[i][j]=f[i-1][j]
<2>可以放,则f[i][j]=f[i-1][j-w[i]]+v[i] /*表示第i件物品如果放。则最大价值=前i-1个物品的价值+第i个物品的价值。前i-1个物品的价值=f[i-1][j-w[i]].其中j-w[i]=背包能承受总重量c-第i个物品重量。v[i]便是第i个物品的价值。*/
最后,综上所述,我们取得背包所能承受最大容量的最大价值:
f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i])
四.实例解释
编号 | 1 | 2 | 3 | 4 |
重量 | 2 | 3 | 4 | 5 |
价值 | 3 | 4 | 5 | 6 |
物品/容量 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 |
3 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 9 |
4 | 0 | 0 | 3 | 4 | 5 | 7 | 8 | 9 | 10 |
下面解释一下上面表格是如何填写的
EX:两个公式:
1 | f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]) | j>=w[i] |
2 | f[i][j]=f[i-1][j] | j<w[i] |
取f[1][1], i=1,j=1,w[1]=2,v[1]=3,此时j<w[1], 采用公式2,带入即得0;
取f[1][2],i=1,j=2,w[1]=2,v[1]=3,此时j=w[1],采用公式1,带入即得3;
取f[1][3], i=1,j=3,w[1]=2,v[1]=3,此时j>w[2], 采用公式1,带入即得3;
......
以此类推,我们能得出表中所有数据,从而得到max价值为f[4][8]=10.表示:四件物品放入背包容量等于8的最大价值为10.
五.代码演绎
核心代码如下:
void Max() {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 8; j++) {
if (j < w[i])
f[i][j] = f[i - 1][j];
else
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
}
}
}
void bag(int i, int j) {
if (i >= 0) {
if (f[i][j] == f[i - 1][j]) {
x[i] = 0;
bag(i - 1, j);
}
else if (j - w[i] >= 0 && f[i][j] == f[i - 1][j - w[i]] + v[i]) {
x[i] = 1;
bag(i - 1, j - w[i]);
}
}
}
//计算价值
完整代码如下:
#include<iostream>
using namespace std;
#include <algorithm>
int w[5] = { 2,3,4,5,6};
int v[5] = { 3,4,5,6,7 };
int f[5][9] = { { 0 } };
int x[5]; //最优解
void Max() {
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 8; j++) {
if (j < w[i])
f[i][j] = f[i - 1][j];
else
f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
}
}
}
void bag(int i, int j) {
if (i >= 0) {
if (f[i][j] == f[i - 1][j]) {
x[i] = 0;
bag(i - 1, j);
}
else if (j - w[i] >= 0 && f[i][j] == f[i - 1][j - w[i]] + v[i]) {
x[i] = 1;
bag(i - 1, j - w[i]);
}
}
}
void output() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 9; j++) {
cout << f[i][j] << ' ';
}
cout << endl;
}
cout << endl;
for (int i = 0; i < 5; i++)
cout << x[i] << ' ';
cout << endl;
}
int main()
{
Max();
bag(4, 8);
output();
return 0;
}
以上就是我对0-1背包的个人见解,也是我第一次写CSDN,大家有问题都可以提出来,我及时修正。