目录
要求恰好装满背包,那么在初始化时除了f[0]为0,其它f[1..V]均设为-∞
如果并没有要求必须把背包装满,而是只希望价格尽量大,初始化时应该将f[0..V]全部设为0。
初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,这个解的价值为0,所以初始时状态的值也就全部为0了。
0-1背包
问题描述:
N件物品和容积为M的背包。
第i件物品的体积为volume [ i ] ,价值为 worth [ i ]。
每种物品只有一件,可以选择放或者不放。
求解将哪些物品装入背包可使价值总和最大。
提示:
采用滚动数组防止超出内存要求
状态转移方程:
f[ i ][v] = max{ f[i-1] [v] , f[i-1][ v-volume[i] ] + worth[i] }
前i件物品放入容量V的背包时的最大价值
= max { 前i -1 件物品放入容量V的背包时的最大价值 ,
【不放入第i件物品,总价值不变 】
前i -1 件物品放入容量V- volume[i] 的背包时的最大价值 + worth [ i ]
【放入第i件物品;那么在放之前的物品是i-1容量是V-volume[i] 价值是f[i-1][ v-volume[i] ] 】
}
空间优化:二维变一维
要保证j-v[i]没被算过的,就是需要J逆序,也就是从大的到小的,不然如果从正序开始的话,前面那些小的值已经都改变过了,而大的值会因为小的值被改变过,而经过二次改变。
f[v] = max{ f[v] , f [ v-volume[i] ] + worth [i] }
最大价值 = max{ 不加入物品i 的上一个最大价值(容量是v),加入物品 i (容量是v-volume[i ]) }
循环,逆推:
// 0 -1 背包
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int main()
{
int n;cin>>n;//N件物品
int m;cin>>m;//背包容积M
int worth[n]; //价值
int volume[n]; //体积
int dp[m];//注意初始化
memset(dp,0,sizeof(dp));//只求最大价值,初始值全部为0
//输入下标i的价值和体积 从0开始
for(int i=0;i<n;++i)
{
cin>>volume[i]>>worth[i];
}
//滚动数组 取前i件物品
for(int i=0;i<n;i++)
{
for(int v=m;v>=volume[i];--v)//
{
//容量V的最大价值 = max{