01背包问题
二维状态方程-代码思路:
struct something{
int index;//物体编号
int m;//物体体积
int v;//物体价值
}
struct bag{
int count;//存放了前count件物品
int volume;//背包体积
}
something a[n+1];//n个物品
int f[n+1][bag.volume+1];//存放状态转移方程,初始化为0
for(int i = 1; i < n; ++i){
for(int j = 1; j < bag.volume; ++j){
if(j < a[n].m)
f[i][j]=f[i-1][j];
else
f[i][j] = max(f[i-1][j], f[i-1][j-a[n].m]+a[n].v);
}
}
return f[n][bag_volume];
动态规划:
- 装不下,不装
- 装得下,判断要不要装
f[n][bag_volume]
代表:在背包体积为bag_volume
的情况下去装前n个物品,最大价值。
动态规划方程:
d p [ i n d e x ] [ v o l u m e ] = { d p [ i n d e x − 1 ] [ v o l u m e ] v o l u m e < m ( 装 不 下 ) max ( d p [ i n d e x − 1 ] [ v o l u m e ] , d p [ i n d e x − 1 ] [ v o l u m e − m ] + v ) v o l u m e ≥ m ( 装 得 下 , 要 不 要 装 ) dp[index][volume] = \begin{cases} dp[index-1][volume] & volume < m (装不下)\\ \max(dp[index-1][volume], dp[index-1][volume-m]+v ) & volume \geq m(装得下,要不要装) \end{cases} dp[index][volume]={dp[index−1][volume]max(dp[index−1][volume],dp[index−1][volume−m]+v)volume<m(装不下)volume≥m(装得下,要不要装)
前面的动态规划使用的是二维数组存放状态,可求任意状态的最大价值。
如果只关心背包放前n
个(即全部)的话,可优化为使用一维数组。
d p [ v o l u m n ] = { d p [ v o l u m n ] max ( d p [ v o l u m n ] , d p [ v o l u m n − m ] + v ) dp[volumn] = \begin{cases} dp[volumn]\\ \max(dp[volumn],dp[volumn-m]+v) \end{cases} dp[volumn]={dp[volumn]max(dp[volumn],dp[volumn−m]+v)
根据二维的状态转移方程可得知,dp[index][volumn]
的更新依赖到dp[index-1][volumn]
,一维数组中的dp[volumn]
实际等价于二维数组的dp[index][volumn]
,所以优化成一维时需要使用逆序,避免dp[volumn]
在被依赖时是dp[index-1][volumn]
。
由于使用了一维数组,第二层for循环改为从bag.volumn
开始逆序,则此时循环判断条件可以改为j>=a[n].m
。
循环条件更改了,则可以边输入边处理而省略存储过程。