今天做了一下01背包问题,重新思考了一下,解决了理解状态转移方程上的坑,而且很多博客或资料,甚至课本都没有给出转移方程的解释,所以理解上还是花了点时间,希望能帮上不太理解状态转移方程的同学们
0-1 背包问题:给定 n 种物品和一个容量为 C 的背包,物品 i 的重量是 weight[i],其价值为 value[i]。
问:应该如何选择装入背包的物品,使得装入背包中的物品的总价值最大?
每个物品只能选择拿或不拿,
定义数组m[N][N],m[i][j]代表背包容量为j时,选择第i件物品后,背包内最大的总价值
当选择第i件物品时,如果背包容量小于物品重量,只能选择不拿。
如果背包容量大于物品重量时,可以选择拿或不拿,如果拿使背包的总价值比不拿使背包的总价值大,则选择拿,
可能很多人会和我有一样有个疑问,这也是这个问题棘手的地方,就是拿不是肯定比不拿的总价值大吗?
但是背包的总容量是有限的,如果选择拿,就可能要面临丢某几件物品的情况,丢多少取决于第i件物品的重量
所以 m[i-1][j], 背包容量小于物品重量
m[i][j]=
max(m[i-1][j],m[i-1][j-weight[i]]+value[i])
解释一下第二个公式
m[i-1][j]就是不拿第i件物品背包最大的价值
m[i-1][j-weight[i]]代表背包容量为j的情况下,要想装下第i件物品,需要留出weight[i]的空间,所以需要找到m[i-1][j-weight[i]],即选择完第i-1件物品且背包剩余空间有weight[i]时背包的最大总价值,然后装入第i件物品,所以再加上value[i],才是拿第i件物品背包内的总价值
然后拿和不拿取最大值
代码如下,其实解释到这步,代码贴不贴也无所谓了
// 01背包.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int main()
{
int weight[N] = { 0 , 1 , 3 , 2 , 6 , 2 }; //物品重量
int value[N] = { 0 , 2 , 5 , 3 , 10 , 4 }; //物品价值
int m[N][N]; //m[i][j] 选择第i件物品时,背包剩余容量为j时可获得的最大价值
int f[N]; //n[i]第i件物品是否被选中
int n = 6; //物品数量
int c = 12; //背包容量
for (int i = 0; i <= n; i++) m[i][0] = 0;
for (int j = 0; j <= c; j++) m[0][j] = 0;
for(int i=1;i<=n;i++){
for (int j = 1; j <= c; j++) {
if (j < weight[i]) { //当剩余容量小于第i件物品的重量时,
m[i][j] = m[i-1][j]; //背包中的总价值为选择完第i-1件物品后的总价值
}
else { //当背包剩余容量大于第i件物品重量时,
m[i][j] = max(m[i-1][j],m[i-1][j-weight[i]]+value[i]); //背包总价值为不装第i件物品的价值和装入第i件物品后的价值的最大值
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= c; j++) {
cout << m[i][j] << " ";
}
cout << endl;
}
for (int i = n; i >= 1; i--) {
if (m[i][c] == m[i - 1][c]) f[i] = 0;
else {
f[i] = 1;
c = c - weight[i];
}
}
for (int i = 1; i <= n; i++) {
cout << f[i] << " ";
}
}
如果帮到你了,我会很开心的