01背包
01背包题目
给了很多个物品,W和V是两个数组,第i个物品重量是W[i],价值是V[i]。背包最大承受重量为n。如何让这个背包装的价值最大。
01背包就是每个物品只有一件。定义一个和(物品总个数+1)的数组,当判断出这个物品需要装进去时候就置为1,不装进去置为0。这个就是这个数组。这也是为啥叫做01背包。
粘贴一个题目过来
int W[6] = {0 , 2 , 5 , 3 , 10 , 4}; //价值
int V[6] = {0 , 1 , 3 , 2 , 6 , 2}; //物体重量
int bagW = 12; //背包承受重量的上限
解题思路
我说的不专业,就题论题把。
简单来说,就是用一个二维数组来解决问题。
我们知道题目给了背包承受重量的上限为n,我们用二维数组的每列保存上限为1到n的情况。
二维数组每一行对应目前存在什么物品,这里包含每行上面所有的物品不包括下面的物品。
二维数组中的每个格子元素就是对应当前存在什么物品,背包最大承受重量的上限所对应的最大价值。
第二个就是判断这个物品是不是应该装进去,装还是不装,这是这个问题的关键。
下面这个方程就是判断装与不装的
if(j>=w[i])
m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
else
m[i][j]=m[i-1][j];
int V[6] = {0 , 2 , 5 , 3 , 10 , 4}; //价值
int W[6] = {0 , 1 , 3 , 2 , 6 , 2}; //物体重量
int bag = 12; //背包承受重量的上限
针对这个题目画出来的二维数组
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
2 | 0 | 2 | 2 | 5 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 |
3 | 0 | 2 | 3 | 5 | 7 | 8 | 10 | 10 | 10 | 10 | 10 | 10 | 10 |
4 | 0 | 2 | 3 | 5 | 7 | 8 | 10 | 12 | 13 | 15 | 17 | 18 | 20 |
5 | 0 | 2 | 4 | 6 | 7 | 9 | 11 | 12 | 14 | 16 | 17 | 19 | 21 |
我们从w[1][1]开始看,因为最初只有物品1且背包上限随着列的 增加我们依次递增。但是我们每个物品都是只有一个。因此,第一行就是从出现2之后后面都为2。
我们要清楚的是每个格子对应的是什么东西,
存在该行以上的物品,该列所表示的背包上限,所对应的最大价值。
我们看w[2][3] 是怎么算出来等于5的。
当背包上限为3时候,第二个物品是对应是(3,5)重量为3价值为5。
执行过程为先判断背包上限能装下物品2不,发现可以就执行if语句
if中拿w[1][0]+5 和 w[1][2]比较大小,大的那填入进去,所以w[2][3] = 5;
主要这一步最关键,它相当于我发现我背包承受重量上限(这里上限指的是每列)大于我这个物品重量可以装下,好那我先回退到没有我这个物品(也就是上一行),我能塞下这个物品的重量(也就是回退对应该物品的重量的列数)所对应的的最大价值+这个物品对应的价值 和我上一行当前列数价值相比较,谁大填谁。
每一行都这么处理就,发现到了右下角就是我们想要求得的最大价值。
简单代码表达下意思也好懂,主要是懂意思就好了
int main()
{
int V[6] = {0,2,5,3,10,4};
int W[6] = {0,1,3,2,6,2};
int m[6][13] = {0};
for(int i=1; i<6; i++)
{
for(int j=1; j<13; j++)
{
if(W[i]>j)
{
m[i][j] = m[i-1][j];
}
else
{
m[i][j] = max(m[i-1][j],m[i-1][j-W[i]]+V[i]);
}
cout<<m[i][j]<<" ";
}
cout<<endl;
}
return 0;
}