背包DP问题
0/1背包
问题模型
给定N个物品,其中第i个物品的体积为Vi,价值为Wi。有一个容积为M的背包。要求放入物品的总体积不超过M的情况下,总价值最高。
状态转移方程
F[i,j]表示从前i个物品里选出了总体积为j的物品放入背包,物品的最大价值和
例题
Description:
在N个数中找出其和为M的若干个数。先读入正整数N(1<N<100)和M(1<M<10000), 再读入N个正数(可以有相同的数字,每个数字均在1000以内), 在这N个数中找出若干个数, 使它们的和是M, 把满足条件的数字组合都找出来以统计组合的个数,输出组合的个数(不考虑组合是否相同)。
Input:
第一行是两个数字,表示N和M。
第二行起是N个数。
Output:
就一个数字,表示和为M的组合的个数。
Sample Input:
4 4
1 1 2 2
Sample Output:
3
容量M,每个元素容积N(i),价值N(i)
我们先按照状态方程来列出代码框架。
先求出基础问题,最大价值是否是M
普通算法空间复杂度为O(MN)
#include<iostream>
using namespace std;
#include<vector>
// 普通算法
void jichu()
{
int N[6] = {
1,1,2,2 };
int M = 4;
int DP[10][10];
// DP数组初状态
if (N[0] <= M)
{
DP[0][0] = N[0];
}
else
{
DP[0][0] = 0;
}
// 用i-1求i,i要从1开始
// N[1]开始
for (int i = 1; i <= 4; i++)
{
for (int j = 0; j <= M; j++)
{
DP[i][j] = DP[i - 1][j];
}
for (int j = N[i]; j <= M; j++)
{
DP[i][j] = max(DP[i][j], DP[i - 1][j - N[i]] + N[i]);
}
}
}
用滚动数组降低开销
因为 i 阶段只与 i-1 阶段有关
我们把阶段i的状态存储在 i&1中
空间复杂度为O(2M)
void gundong()
{
int N[6] = {
7,1,2,2 };
int n = 4;
int M = 6;
int DP[2][10];
if (N[0] <= M)
{
DP[0][0] = N[0];
}
else
{
DP[0][0] = 0;
}
for (int i = 1; i <= 4; i++)
{
for (int j = 0; j <= M; j++)
{
DP[i & 1][j] = DP[(i - 1