背包问题
来源:互联网 发布:做淘宝客需要多少成本 编辑:程序博客网 时间:2024/05/16 01:08
完全背包问题
一个旅行者随身携带一个背包. 可以放入背包的物品有n 种, 每种物品的重量和价值分别为 wi , vi . 如果背包的最大重量限制是 b, 每种物品可以放多个. 怎样选择放入背包的物品以使得背包的价值最大 ? 不妨设上述 wi , vi , b 都是正整数.
解题思路
目标函数:装入背包的所有物品的价值达到最大
约束条件:装入背包的所有物品的重量<=b
F[k][y] 表示只允许装入前k种物品,且背包重量不超过y时背包内所有物品的最大价值。此时有两种选择:
- 不装第k种物品,此时只能从前k-1件物品中选,F[k][y] = F[k-1][y]
第k种物品至少装一件,(如果先装入一件第k种物品,此时剩余重量y-wk,由于每种物品可以装入多件,所以任然要在前k种物品中选择)此时F[k][y] = F[k][y-wk] + vk;
要让背包内物品价值达到最大,则递推方程:F[k][y] = max{F[k-1][y] , F[k][y-wk] + vk}
边界条件:
F[0][y] = 0;
F[k][0] = 0;
F[k][y] = 负无穷, if y<0
F[1][y] = (y/w1)*v1;
标记函数mark[k][y] 用于标记当F[k][y] 价值达到最大时,背包里装入物品的最大编号(此函数需要从后向前遍历==)
如果:F[k-1][y] > F[k][y-wk] + vk,则mark[k][y] =mark[k-1][y]
如果:F[k-1][y] < F[k][y-wk] + vk,则mark[k][y] =k
边界条件:
mark[k][0] = 0
mak[0][k] = 0
时空复杂度
备忘录F[k][y] 中,k与y的组合有 n*b种,每种的计算时间为常数
时间复杂度:O(n*b)
空间复杂度:O(n*b)
实现
package com.cn;import java.util.Scanner;public class KnapsackProblem { public static void main(String []args){ int n = 0;//the number of the kinds of goods int b = 0;//backpack maximum weight limit Scanner sc = new Scanner(System.in); n = sc.nextInt(); b = sc.nextInt(); int[] w = new int[n+1];//the weight of each goods int[] v = new int[n+1];//the value of each goods int[][]mark = new int[n+1][b+1]; for(int i = 1;i <= n;i ++){ if(sc.hasNextInt()){ w[i] = sc.nextInt();//实际存储的下标是从1开始的 } } for(int i = 1;i<=n;i++){ if(sc.hasNextInt()){ v[i] = sc.nextInt();//实际存储的下标是从1开始的 } } System.out.println(MaxValue(n,b,w,v,mark)); Sign(mark,n,b,w); } public static int MaxValue(int n,int b,int[] w,int[] v,int[][] mark){ int[][] F = new int[n+1][b+1];//实际存储的下标是从1开始的 for(int i=1;i<=b;i++){ F[0][i] = 0; F[1][i] = i/w[1]*v[1]; mark[0][i] = 0; } for(int i=1;i<=n;i++){ F[i][0] = 0; mark[i][0] = 0; } for(int k=1;k<=n;k++){ for(int y=1;y<=b;y++){ if(y < w[k]){ F[k][y] = F[k-1][y]; mark[k][y] = mark[k-1][y]; }else{ F[k][y] = F[k-1][y] > (F[k][y-w[k]]+v[k]) ? F[k-1][y] : (F[k][y-w[k]]+v[k]); mark[k][y] = F[k-1][y] > (F[k][y-w[k]]+v[k]) ? mark[k-1][y] : k; } } } return F[n][b]; } //计算最终装进的每件物品的数量 public static void Sign(int[][] mark,int n,int b,int[] w){ int[] num = new int[n+1]; for(int i = 1;i<=n;i++){ num[i] = 0; } int s = mark[n][b]; int t = b; while(mark[s][t] != 0){ t = t - w[s]; num[s]++; while(mark[s][t] == s){ num[s]++; t = t - w[s]; } s = mark[s][t]; } for(int i=1;i<=n;i++){ System.out.println("item" + i + ":" + num[i]); } }}
空间优化
F[k][y] = max{F[k-1][y] , F[k][y-wk] + vk}
使用F[y]来表示F[k][y]、以及F[k-1][y]
使用F[y-wk]来表示F[k][y-wk]
package com.cn;import java.util.Scanner;public class KnapsackProblemOptimization { public static void main(String[] args) { // TODO Auto-generated method stub int n = 0;//the number of the kinds of goods int b = 0;//backpack maximum weight limit Scanner sc = new Scanner(System.in); n = sc.nextInt(); b = sc.nextInt(); int[] w = new int[n+1];//the weight of each goods int[] v = new int[n+1];//the value of each goods int[][]mark = new int[n+1][b+1]; for(int i = 1;i <= n;i ++){ if(sc.hasNextInt()){ w[i] = sc.nextInt(); } } for(int i = 1;i<=n;i++){ if(sc.hasNextInt()){ v[i] = sc.nextInt(); } } System.out.println(MaxValue(n,b,w,v,mark)); }public static int MaxValue(int n,int b,int[] w,int[] v,int[][] mark){ int[] F = new int[b+1]; for(int i=1;i<=b;i++){ F[i] = i/w[1]*v[1]; mark[0][i] = 0; } for(int i=1;i<=n;i++){ F[i] = 0; mark[i][0] = 0; } for(int k=2;k<=n;k++){ for(int y=1;y<=b;y++){ if(y < w[k]){ mark[k][y] = mark[k-1][y]; }else if(F[y-w[k]]+v[k] >= F[y]){ F[y] = F[y-w[k]]+v[k]; mark[k][y] = k; } } } return F[b]; }}
0-1背包问题
0-1背包问题与完全背包问题的区别就是:每种物品只有一件(要么放进背包,要么不放)
解题思路
完全按照上面的思路,但是:
F[k][y]任然有两种选择:
- 不装第k种物品:F[k][y] = F[k-1][y]
- 装第k种物品:F[k][y] = F[k-1][y-wk] + vk
此时F[k][y] = max{F[k-1][y] , F[k-1][y-wk] + vk}
边界条件:
F[0][y] = 0;
F[k][0] = 0;
F[k][y] = 负无穷, if y<0
F[1][y] = v1 , if y>w1 ,=0, if y
实现
package com.cn;import java.util.Scanner;public class KnapSack01 { public static void main(String[] args) { // TODO Auto-generated method stub int n = 0;//the number of the kinds of goods int b = 0;//backpack maximum weight limit Scanner sc = new Scanner(System.in); n = sc.nextInt(); b = sc.nextInt(); int[] w = new int[n+1];//the weight of each goods int[] v = new int[n+1];//the value of each goods int[][]mark = new int[n+1][b+1]; for(int i = 1;i <= n;i ++){ if(sc.hasNextInt()){ w[i] = sc.nextInt(); } } for(int i = 1;i<=n;i++){ if(sc.hasNextInt()){ v[i] = sc.nextInt(); } } System.out.println(MaxValue(n,b,w,v,mark)); Sign(mark,n,b,w); } public static int MaxValue(int n,int b,int[] w,int[] v,int[][] mark){ int[][] F = new int[n+1][b+1]; for(int i=1;i<=b;i++){ F[0][i] = 0; if(i >= w[1]){ F[1][i] = v[1]; }else{ F[1][i] = 0; } mark[0][i] = 0; } for(int i=1;i<=n;i++){ F[i][0] = 0; mark[i][0] = 0; } for(int k=1;k<=n;k++){ for(int y=1;y<=b;y++){ if(y < w[k]){ F[k][y] = F[k-1][y]; mark[k][y] = mark[k-1][y]; }else{ F[k][y] = F[k-1][y] > (F[k-1][y-w[k]]+v[k]) ? F[k-1][y] : (F[k-1][y-w[k]]+v[k]); mark[k][y] = F[k-1][y] > (F[k][y-w[k]]+v[k]) ? mark[k-1][y] : k; } } } return F[n][b]; }//计算最终装进的每件物品的数量 public static void Sign(int[][] mark,int n,int b,int[] w){ int s = mark[n][b]; int t = b; while(mark[s][t] != 0){ System.out.println("item" + s); t = t - w[s]; s = mark[s][t]; } }}
二维0-1背包问题
二维背包问题:每件物品有重量 wi 和体积 ti, i =1, 2, … , n,背包总重不超过 b,体积不超过V, 如何选择物品以得到最大价值.
递推方程
若j>=wi 且 k>=ci
m[i,j,k] = max{m[i-1,j,k] , m[i-1,j-wi,k-ci] + vi}
否则
m[i,j,k] = m[i-1,j,k]
以上内容整理自屈婉玲老师的算法设计与分析,如有不足,欢迎交流
- 【无限背包】背包问题
- 背包问题---01背包
- 背包问题--部分背包
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 背包问题
- 《CTCI》1.7 二维数组的含0元素所在行列清零
- Linux平台静态库、动态库的一些笔记
- 电工的前途
- [刷题]Reorder List
- 对汇编中条件转移指令的认识
- 背包问题
- meta标签
- 转:缺点是另外一个优点
- fragment之间的切换实例
- Android模拟器中使用SD卡
- 只能上qq不能上网的问题,跟adsafe有关
- 对C++中运行时类型识别的认识
- 木炭机设备使用寿命短是什么造成的?
- C语言控制输出不按数据类型输出的问题