背包问题
有n 种不同的物品,每个物品有两个属性,size 体积,value 价值,现在给一个容量为 w 的背包,问最多可带走多少价值的物品。
情况一:物品的价值和重量给出,物品的数量均为1,背包的容量给出,背包不一定装满。
1.定义数据变量
int n;物品的总数
int total_weigh;//背包的容量
int w[];//各个物品的重量
int v[];//各个物品的价值
int c[i][j];前i个物品放入容量为j的背包的最大价值
2.初始化
int c[i][j] = {0};
3.两个主要的for循环
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= total_weight; j++) {
if (w[i] > j) {
// 说明第i件物品大于背包的重量,放不进去
c[i][j] = c[i-1][j];
} else {
//说明第i件物品的重量小于背包的重量,所以可以选择第i件物品放还是不放
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]];
}
}
}
}
节省空间:一维数组
for(int i = 1; i <= n; ++i)
{
for(int v = V; v >= w[i]; --v) //背包的重量从大到小,从而避免了覆盖前面的数据
{
f[v] = max(f[v], f[v-w[i]]+p[i]);
}
}
情况二:物品的价值和重量给出,物品的数量均为1,背包的容量给出,背包一定装满。
1.定义数据变量
int n;物品的总数
int total_weigh;//背包的容量
int w[];//各个物品的重量
int v[];//各个物品的价值
int f[i][j];前i个物品放入容量为j的背包的最大价值
2.初始化
for (int i = 0;i <= N;i++) //枚举物品
{
for (int j = 0;j <= V;j++) //枚举背包容量
{
f[i][j] = MinNum; (一个比较大的负数)
}
}
for (int i = 0;i <= N;i++)
{
f[i][0] = 0;//背包容量为0时为合法状态
}
3.两个循环
for (int i = 1;i <= N;i++) //枚举物品
{
for (int j = 1;j <= V;j++) //枚举背包容量
{
f[i][j] = f[i - 1][j];
if (j >= weight[i])
{
f[i][j] = max(f[i - 1][j],f[i - 1][j - weight[i]] + value[i]);
}
}
}
//通过是否为负数来判断能否装满
节省空间:一维数组
for (int i = 1;i <= N;i++) //枚举物品
{
for (int j = V;j >= weight[i];j--) //枚举背包容量,防越界,j下限为 weight[i]
{
f[j] = max(f[j],f[j - weight[i]] + value[i]);
}
}
情况三:物品的价值和重量给出,物品的数量为任意个,背包的容量给出,背包不一定装满。
dp[ i+1 ][ j ] = max ( dp[ i ][ j ], dp[ i +1 ][ j - ci ] + wi );
总结
- 背包问题解决的核心问题是:如何搭配各个物品
- 背包是否装满决定初始化的形式,如果需要装满的话,则初始化均为大负数,背包容量为0的情况初始化为1。