引言
对于通常的0-1揹包问题来说,只用考虑重量以及放与不放这两个因素,今天看到一道问题加入了对于体积因素的考虑,即最终结果要求重量体积都不大于要求的值,且价值最大。
原题如下:
小刘去春游,有5个物品,已知各物品的质量、体积、个数、价格(各项数值可以自己找一组带一下,思想都是一样的),总共能带500cm³和100kg的物品,求能带物品的最大价值。请用递归算法解决。
递归解法
很明显这是在经典的0-1揹包问题上加了个干扰条件,其实如果真的完全了解0-1揹包的话就会发现其实本质都是一样的,不过是填格子,做选择,最后组合成找出最优解而已。
经典的0-1揹包递归式子k如下所示:
假设c[i,w]代表揹包中物品为i个且揹包承载重量为w时的最大价值。那么对于每一个物品,是否要放入揹包就可以写作如下递归式子:(vi表示当前物品价值)
c[i,w] = c[i-1][w] > c[i-1][w-wi]+vi ?c[i-1][w]:c[i-1][w-wi]+vi;
那么现在加入一个体积因素这个式子就可以写成:
假设c[i,w,v]代表揹包中物品为i个且揹包承载重量为w,体积为v时的最大价值。那么对于每一个物品,是否要放入揹包就可以写作如下递归式子:(bi表示当前物品价值)
c[i,w,v] = c[i-1][w][v] > c[i-1][w-wi][v-vi]+bi ?c[i-1][w][v]:c[i-1][w-wi][v-vi]+bi;
ok,既然递推式子出来了,那么递推函数代码也就呼之欲出了。在此以java举例
public class Main{
static int W = 100;
static int number = 5;
static int V = 500;
static int VALUE[] = {60, 20, 10, 60, 100};
static int WEIGHT[] = {20, 30, 50, 60, 80};
static int CAPACITY[] = {68,100,200,30,340};
public static void main(String[] args)
{
int maxValue = calculate(number-1, W,V);
System.out.println(maxValue);
}
public static int calculate(int i, int j , int k)
{
int r1 = 0;
int r2 = 0;
int r = 0;
if (i == -1)
{
return 0;
}
if(j >= WEIGHT[i] && k >= CAPACITY[i])
{
r1 = calculate(i-1,j - WEIGHT[i],k-CAPACITY[i]) + VALUE[i];
r2 = calculate(i-1,j,k);
r = (r1>r2)?r1:r2;
}
return r;
}
}
从递归角度看,其实和经典0-1揹包差不多,无非是在递归判断式,多加个判断而已,但是如果换成非递归算法那就是相当于一个3*3的填格子问题了。不过问题本质没有改变,依然是拥有多个交叉子问题,然后做选择,将一系列子问题递推最终得出最优解的过程,即动态规划的经典思路。
ok,好久没更新写过博客类的东西了,发现了这个问题感觉回想起大学写上算法课的思考过程,特此记录一下,顺带复习下0-1揹包。