动态规划-01基础背包

最近在做华为OJ题,做到“购物单”一题,突然感觉一脸懵逼,有点熟悉却又思维混乱,研究了一下,发现是由来已久的背包问题,遂详细的了解一下该算法。这里将最简单的背包问题——即无重复选取,每个物品仅放一次,其核心方程如下:

f[i][j] = max{f[i-1][j],f[i-1][j-[w[i-1]]]+v[i-1](j>=w[i-1])}

假设:定义可容纳总重量W =10 Kg,物品种类 N = 4,每件物品重量w[i],对应价值v[i],求解在可容纳重量范围内如何选取可获最大价值。

本题具体题目:


可能出现的背包情况:


上述表格从上到下,从左到右生成。

其中,每一行对应每一个种类,例如第一行,代表该背包中仅放a物品,所以当背包可容纳重量为0和1 Kg时,均无法放置a物品,总价值为0,而当背包容量为2 Kg时,则刚好容纳a物品,则其总价值为3,以此类推,生成该表格。

基于《背包九讲》,涉及该基础背包问题可以会出现这么两种情况:1,背包不需要完全装满,只需要宗价值最大化,此时应该使用一维数组,将c[i]全部初始化为0;2,要求背包恰好装满,在该情况下获取最大价值,此时,除此c[0]为0,其余则均初始化为无穷小。

其Java代码如下:

//一维数组,背包不必完全装满求最大价值
	private static int[] BP_method01_1D(int m,int n,int[] w,int[] v){
		int c[] = new int[m+1];
		for (int i = 0; i < m+1; i++) {
			c[i] = 0;//不必完全装满,则全部初始化为0
		}
		for (int i = 0; i < n; i++) {//限定物品种类,无重复
			for (int j = m; j >= w[i]; j--) {//限定总重量
				c[j] = Math.max(c[j-w[i]] + v[i], c[j]); 
			}
		}
		return c;
	}
//一维数组,背包恰好完全装满求最大价值
	private static int[] BP_method01_1DC(int m,int n,int[] w,int[] v){
		int c[] = new int[m+1];
		for (int i = 1; i < m+1; i++) {
			c[i] = Integer.MIN_VALUE;//必须完全装满,则除0以外均初始化为无穷小
		}
		for (int i = 0; i < n; i++) {//限定物品种类,无重复
			for (int j = m; j >= w[i]; j--) {//限定总重量
				c[j] = Math.max(c[j-w[i]] + v[i], c[j]); 
			}
		}
		return c;
	}
// 01 基础背包问题,二维数组
	private static int[][] BP_method(int m,int n,int[] w,int[] v){
		int c[][] = new int[n+1][m+1];
		for (int i = 0; i < n+1; i++) {
			c[i][0] = 0;
		}
		for (int i = 0; i < m+1; i++) {
			c[0][i] = 0;
		}
		for (int i = 1; i <= n; i++) {//限定物品种类,无重复
			for (int j = 1; j <= m; j++) {//限定总重量
				if (j >= w[i-1]) {
					c[i][j] = Math.max(c[i-1][j-w[i-1]] + v[i-1], c[i-1][j]); 
				}else {
					c[i][j] = c[i-1][j];
				}		
			}
		}
		return c;
	} 

其输出结果如下:

一维不装满:
0 0 5 5 8 9 9 12 12 14 15 
一维装满:
0 -2147483648 5 4 8 9 -2147483639 12 10 14 15 
二维选取:
0  3  3  3  3  3  3  3  3  3  
0  3  4  4  7  7  7  7  7  7  
0  5  5  8  9  9  12  12  12  12  
0  5  5  8  9  9  12  12  14  15  

猜你喜欢

转载自blog.csdn.net/xiaoxun2802/article/details/80000304