0/1背包问题:
由于前段时间研究了动态规划,今天就利用动态规划来分析及解决0/1背包问题!
问题描述:一个旅行者有一个最多能用M公斤的背包,现在有N件物品,
它们的重量分别是W1,W2,...,Wn,
它们的价值分别为v1,v2,...,vn.
若每种物品只有一件求旅行者能获得最大总价值?
问题分析:问题求的是最大的价值,我们定义f[i,j]表示前i种物体放进容量为j的背包里面获取到最大的价值,定义f[I,j]是子问题,显然,子问题具有重叠性,具有最优解性质,所以,此问题可以利用动态规划来解决,分析得到子问题最优解f[I,j]具有以下性质:
f[i,j]= 0,{i=0 OR j=0}-----------------------------临界值
f[i,j]= f[i-1,j],{j<wi}----------------------------递归公式1
f[i,j]= max(f[i-1,j],f[i,j-wi]+vi),{j>wi}----------递归公式2
则n*m的f表格来记录各个过程的值(利用空间来换取时间)
下面我举例来说明,如果w={3,6,5} v={4,3,6} n=3,m=15
表格如图所示:
F[i][j] | J=0 | J=1 | J=2 | J=3 | J=4 | J=5 | J=6 | V7 | V8 | J=9 |
I=0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
I=1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
I=2 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 7 |
I=3 | 0 | 0 | 0 | 4 | 4 | 6 | 6 | 6 | 10 | 10 |
如是我们利用java语言来描述o-1背包问题
public class BeiBao {
public int beiBaoFun(int n, int m, int[] w, int[] v) {//n个物体,容量为m的背包,wi表示第i个的重量,v表示第i个中价值。
/* f[i,j]表示取i件商品填充一个容积为j的背包的最大价值,显然问题的解就是f[n,m]*//*
* 显然:f[i,j]=f[i-1,j] {j<Vi} 或者 max{f[i-1,j],f[i,j-Vi]+Pi} {j>=Wi} 或者 0 {i=0 OR j=0}
*/
int[][] f = new int[n + 1][m + 1];
for (int j = 0; j <= m; j++) {
f[0][j] = 0;/* 初始化:当i=0时,f[0][j]=0 */
}
for (int i = 0; i <= n; i++) {
f[i][0] = 0;/* 初始化:当j=0时,f[i][0]=0 */
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (w[i] <= j) { /* 如果当前物品的容量小于背包容量 */
f[i][j] = max(v[i] + f[i - 1][j - w[i]], f[i - 1][j]);
} else {
f[i][j] = f[i - 1][j];
}
}
}
return f[n][m];
}
private int max(int i, int j) {
return i > j ? i : j;
}
public static void main(String[] args) {
BeiBao bb = new BeiBao();
int[] w = { 0, 3, 6, 5 };/* 注意:由于算法的设计问题,把第0项也要设计上去但是我在计算时候只不把他考虑进去 */
int[] v = { 0, 4, 3, 6 };
int res = bb.beiBaoFun(w.length - 1, 15, w, v);
System.out.println(res);
}
}
过程分析:
0 0 4 4 4 4 4 4 4 4 4 4 4 4 4
0 0 4 4 4 4 4 4 7 7 7 7 7 7 7
0 0 4 4 6 6 6 10 10 10 10 10 10 13 13
欢迎大家交流~~~