动态规划——背包问题

动态规划——背包问题(运输货物问题)

先学习 01背包问题
背包问题可大致分为【完全背包问题】和【多重背包问题】
动态规划——背包问题_第1张图片

分析问题:
原问题:在满足重量约束的条件下,将这 m 件物品选择性的放入容量位W的背包中所能获得的最大利润
子问题:在满足重量约束的条件下,将 前 i(i<=m)件物品选择性的放入容量为 j(j<=W)的背包中所能获得的最大利润
定义状态: f(i,j)为前 i 件物品选择性放入 容量为 j (j<= W)中获得最大利润。那么 f(m,W)就是我们的原问题。
存在两个参数,所以创建一个二维DP数组。

vi表示第 i 件物品的价值,wi 表示第 i 件物品的重量

这里假设物品重量为正整数(非正整数,可以试着转化单位化为整数或其他方法,还在学习中)

寻找状态转移方程
边界条件(初始条件)

  • 第一行: f(1,i)表示把第1件物品放入容量为 j 的背包所能获取的最大值,显然 j >= w1,即只要背包的容量>=第1件物品的重量(装的下)时,f(1,j)=v1,否则f(1,j)=0;
  • 第一列: f(i,1)表示把前 i 件物品放入容量为 1的背包所能获取的最大值,这里物品重量都是正整数,因此我们先找前i件物品中重量为1的物品,然后再找其中v价值最大的物品,f(i,1)=vi,如果前i件物品不存在重量为1 的物品时,f(1,j)=0

构建方程:

  • 当 i > 1 和 j > 1 的情况: 考虑以下:由一个容量大小为j的背包,已经规划好了 前面 i-1 件物品的装载方案,现在你只需要考虑装不装第 i 件物品。

所以接下来,考虑两种情况:

(1)第 i 件物品重量wi > 背包容量 j :我们只能放弃。那就是还是和前面的装载方案一样,不变,即 f(i,j)=f(i-1,j)与前 i-1 件物品选择放入背包一样。
(2)第 i 件物品的重量wi < 背包容量 j :也是两种情况:装第 i 件,判断,看背包剩下的容量 j-wi ,装的下就装,装不下就不装。看可以装下的价值f(i-1,j-wi)。
即 f(i,j)= max{ f(i-1,j),vi + f(i-1,j-wi)}
注意:当 j = wi 时,f(i-1,j-wi)=0;

转移方程:
动态规划——背包问题_第2张图片

代码实现:

	public static void valueMax(int[] weight, int[] value, int capacity) {
		//这里 weight和value是一样从的。   表示 物品的个数
		int num = value.length;
		int[][] dp = new int[weight.length+1][capacity+1];
		//记录放入商品的情况
		int[][] path = new int[weight.length+1][capacity+1];
				
		// 第一行  将可以放下的 第一物品 放入
		for (int j = 0; j < dp.length; j++) {
			dp[j][0] = 0;
		}
		// 第一列   背包容量为1的 ,可以装下哪些物品
		for (int i = 0; i < dp[0].length; i++) {
			dp[0][i] = 0;
		}

		// 然后从 第 一行和第一列 开始 
		for (int i = 1; i < dp.length; i++) {
			for (int j = 1; j < dp[0].length; j++) {
				if (j >= weight[i-1]) {	//这里因为是从第一行开始 使用对应的第一个是  weight[i-1]
					// 还是 应为 我们 下标是从 1开始的,所以对应的公式需改动  即 物品的重量和价格需 下标要减1
					//dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
					
				//	dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i-1]] + value[i-1]);	
					
					// 为了 存储 选择 放入背包的是哪些物品 所以使用 选择来实现
					if(dp[i-1][j] < dp[i-1][j-weight[i-1]]+value[i-1]) {
						dp[i][j] = dp[i-1][j-weight[i-1]]+value[i-1];
						path[i][j] = 1;
					}else {
						dp[i][j] = dp[i-1][j];
					}
					
				} else {
					dp[i][j] = dp[i - 1][j];
				}
				
			}
		}

		System.out.println("动态规划表如下:");
		for (int i = 0; i < dp.length; i++) {
			for (int j = 0; j < dp[i].length; j++) {
				System.out.print(dp[i][j] + "\t");
			}
			System.out.println();
		}	
		int i=path.length-1;
		int j=path[0].length-1;
		while(i>0 && j>0) {
			if(path[i][j] == 1) {
				System.out.printf("第%d个商品放入背包\n",i);
				j-=weight[i-1];
			}
			i--;
		}
	}

你可能感兴趣的:(算法,学习,动态规划)