动态规划 0-1背包问题和时间轴问题
2017-10-13 22:07
225 查看
背包问题:有N件物品和一个承受重量为c的背包。第i件物品的费用是v[i],重量是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
基本思路:
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放
假设maxValue[i][j]表示前i件物品恰放入此时承重为j的背包可以获得的最大价值。那么容易得到状态转移方程是:
maxValue[i][j]=Max{maxValue[i-1][j],maxValue[i-1][j-weight[i]]+value[i]}
maxValue[i-1][j]表示此时背包放不下物品i
maxValue[i-1][j-weight[i]]+value[i] 可以放下i物品,需要退回到i-1时刻来添加i的价值
int w[]={0,4,5,6,2,2};//第一位是0,是为了方便从1开始计算
int value[]={0,6,4,5,3,6};
int a[][]=new int[6][11];
打表:图片引用其他博主http://blog.csdn.net/mu399/article/details/7722810
这里从左到右边,有底向上开始
先是按行来计算
e这一行,e的重量为4,所以在背包重量为j=1,2,3时候都是价值为0
如下图例 从上到下开始计算
代码是用第一个图中数据,是从上向下开始的 abe被最终选择
上面的直接得到了最大值,如何得到选了哪些商品
最优解即是maxValue(number,weight)=maxValue(5,10)=15,但还不知道解由哪些商品组成,故要根据最优解回溯找出解的组成,根据填表的原理可以有如下的寻解方式:
1) maxValue(i,j)=maxValue(i-1,j)时,说明没有选择第i 个商品,则回到maxValue(i-1,j);
2)maxValue[i][j]=maxValue[i-1][j-weight[i]]+value[i],说明装了第i个商品 输出i,该商品是最优解组成的一部分,随后我们得回到装该商品之前,即回到maxValue(i-1,j-w(i));
3) 一直遍历到i=0结束为止,所有解的组成都会找到。
代码
空间优化问题:下面的一些表示被简写 weight=w value=v V=maxVlaue
上面的算法的时间o(numbers*背包承重),空间也是这个,因为用了一个maxValue[i][j]数组
这里用二维实际上是为了好得到哪些商品是被最终装进包中
可以只用一维数组
、
l) 空间优化,每一次V(i)(j)改变的值只与V(i-1)(x) {x:1…j}有关,V(i-1)(x)是前一次i循环保存下来的值;
因此,可以将V缩减成一维数组,从而达到优化空间的目的,状态转移方程转换为 B(j)= max{B(j), B(j-w(i))+v(i)};
并且,状态转移方程,每一次推导V(i)(j)是通过V(i-1)(j-w(i))来推导的,所以一维数组中j的扫描顺序应该从大到小(capacity到0),否者前一次循环保存下来的值将会被修改,从而造成错误。
一维数组因为每次会进行覆盖,所以得到不到具体是哪个商品被装进口袋里
图例:
第一组出来因为放不下之外都是第一个物品的价值
第二组 b[10]=Max{b[10]=6,b[10-w[2]]+v[2]=b[10-2]+3=6+3=9} 按照规则排序
时间轴问题 看这个博客
http://blog.csdn.net/hongchh/article/details/52914507
基本思路:
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放
假设maxValue[i][j]表示前i件物品恰放入此时承重为j的背包可以获得的最大价值。那么容易得到状态转移方程是:
maxValue[i][j]=Max{maxValue[i-1][j],maxValue[i-1][j-weight[i]]+value[i]}
maxValue[i-1][j]表示此时背包放不下物品i
maxValue[i-1][j-weight[i]]+value[i] 可以放下i物品,需要退回到i-1时刻来添加i的价值
int w[]={0,4,5,6,2,2};//第一位是0,是为了方便从1开始计算
int value[]={0,6,4,5,3,6};
int a[][]=new int[6][11];
打表:图片引用其他博主http://blog.csdn.net/mu399/article/details/7722810
这里从左到右边,有底向上开始
先是按行来计算
e这一行,e的重量为4,所以在背包重量为j=1,2,3时候都是价值为0
如下图例 从上到下开始计算
代码是用第一个图中数据,是从上向下开始的 abe被最终选择
/** * * @param maxValue maxValue[i][j]表示在承重为j的包中放的前i个物品的最大价值 * @param maxWeight 背包的最大承重 * @param goods_number 商品的个数 * @param weight 商品的重量数组 * @param value 商品的价值数组 */ public void GetValue(int maxValue[][], int maxWeight,int goods_number,int weight[],int value[]){ for(int i=1;i<=goods_number;i++){ for(int j=1;j<=maxWeight;j++){ if(j>=weight[i]){//如果此时背包的承重>=商品的重量 if(maxValue[i-1][j]>maxValue[i-1][j-weight[i]]+value[i]) maxValue[i][j]=maxValue[i-1][j];//不装第i个物品 else{ maxValue[i][j]=maxValue[i-1][j-weight[i]]+value[i];//把第i个装进去 // a1[i]=1; } } else{ maxValue[i][j]=maxValue[i-1][j]; } } } System.out.println("最大价值:"+maxValue[goods_number][maxWeight]); //prints(maxValue); }
上面的直接得到了最大值,如何得到选了哪些商品
最优解即是maxValue(number,weight)=maxValue(5,10)=15,但还不知道解由哪些商品组成,故要根据最优解回溯找出解的组成,根据填表的原理可以有如下的寻解方式:
1) maxValue(i,j)=maxValue(i-1,j)时,说明没有选择第i 个商品,则回到maxValue(i-1,j);
2)maxValue[i][j]=maxValue[i-1][j-weight[i]]+value[i],说明装了第i个商品 输出i,该商品是最优解组成的一部分,随后我们得回到装该商品之前,即回到maxValue(i-1,j-w(i));
3) 一直遍历到i=0结束为止,所有解的组成都会找到。
代码
//开始调用 i=5,j=10 void FindWhat(int i,int j)//寻找解的组成方式 { if(i>0) { if(maxValue[i][j]==maxValue[i-1][j])//相等说明没装 { FindWhat(i-1,j); } else if( j-w[i]>=0 && maxValue[i][j]==maxValue[i-1][j-weight[i]]+value[i] ) { System.out.println(i);//这里是逆序输出所得到的商品序号 FindWhat(i-1,j-weight[i]);//回到装包之前的位置 } } }
空间优化问题:下面的一些表示被简写 weight=w value=v V=maxVlaue
上面的算法的时间o(numbers*背包承重),空间也是这个,因为用了一个maxValue[i][j]数组
这里用二维实际上是为了好得到哪些商品是被最终装进包中
可以只用一维数组
、
l) 空间优化,每一次V(i)(j)改变的值只与V(i-1)(x) {x:1…j}有关,V(i-1)(x)是前一次i循环保存下来的值;
因此,可以将V缩减成一维数组,从而达到优化空间的目的,状态转移方程转换为 B(j)= max{B(j), B(j-w(i))+v(i)};
并且,状态转移方程,每一次推导V(i)(j)是通过V(i-1)(j-w(i))来推导的,所以一维数组中j的扫描顺序应该从大到小(capacity到0),否者前一次循环保存下来的值将会被修改,从而造成错误。
//空间优化为o(n) public void GetValue2(int maxValue[], int maxWeight,int goods_number,int weight[],int value[]){ for(int i=1;i<=goods_number;i++){ for(int j=maxWeight;j>=0;j--){//必须是要从大到小 if(j>=weight[i]){//如果此时背包的承重>=商品的重量 if(maxValue[j]>maxValue[j-weight[i]]+value[i]) maxValue[j]=maxValue[j];//不装第i个物品 else{ maxValue[j]=maxValue[j-weight[i]]+value[i];//把第i个装进去 // a1[i]=1; } } else{ maxValue[j]=maxValue[j]; } } } System.out.println("最大价值:"+maxValue[maxWeight]); //prints(maxValue); }
一维数组因为每次会进行覆盖,所以得到不到具体是哪个商品被装进口袋里
图例:
第一组出来因为放不下之外都是第一个物品的价值
第二组 b[10]=Max{b[10]=6,b[10-w[2]]+v[2]=b[10-2]+3=6+3=9} 按照规则排序
时间轴问题 看这个博客
http://blog.csdn.net/hongchh/article/details/52914507
相关文章推荐
- 动态规划之背包问题
- 0-1 背包问题 动态规划
- PHP动态规划解决0-1背包问题实例分析
- 算法导论16.2-2--动态规划(0-1背包问题)
- 【动态规划】0/1背包问题
- 动态规划--0 1 背包问题
- 动态规划---->0/1背包问题
- 动态规划解决背包问题
- 【动态规划】常见背包问题合集
- [51NOD - 1085] 背包问题(动态规划)
- 动态规划——背包问题
- 【动态规划/多重背包问题】POJ2392-Space Elevator
- 动态规划之0-1背包问题
- 动态规划0-1背包问题
- 动态规划——背包问题
- hdu 4501 动态规划 + 费用背包问题
- 贪婪算法、递归计算、动态规划背包问题
- 背包问题——动态规划
- 动态规划——背包问题
- 设计算法,在O(n)时间内求解分数背包问题