彻底 搞懂01背包,完全背包,多重背包问题

1,548 阅读2分钟
参考链接:blog.csdn.net/lanyu_01/ar…

问题描述:
一个背包的总容量为V,现在有n类物品,第i类物品的重量为weight[i],价值为value[i],那么往背包里装物品,使得包内的物品总价值最大。主要有三种装法:

  1. 0-1背包:每类物品最多只能装一次;
  2. 完全背包:物品无限量;
  3. 多重背包:每类物品有个数限制,第i类物品有num[i]个;

1,0-1背包

  1. 使用动态规划求解,初始化dp[n+1][v+1],dp[i][j]代表前i件物品使用j容量的背包的物品最大价值;这样我们求dp[n][v]就是我们想要的结果;
package woek1;

import java.util.Scanner;

public class pack0_1 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int v =sc.nextInt();
		int[] weight = new int[n];
		int[] value = new int[n];
		
		
		for(int i = 0;i<n;i++) {
			weight[i] = sc.nextInt();
			value[i] = sc.nextInt();
		}
		
		int[][] dp = new int[n+1][v+1];
		for(int i = 1;i<=n;i++)
			for(int j = 1;j<v+1;j++) {
				//背包容量大于当前物品重量时;选择是否选择此物品放入背包
				//注意下标是从1开始的,当前应该-1;
				if(j>=weight[i-1]){
					dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i-1]]+value[i-1]);
				} else {
					//不然直接不放入背包
					dp[i][j] = dp[i-1][j];
				}
			}
		System.out.println(dp[n][v]);
	}
}

0-1背包优化
使用一维数组dp[v+1],dp[i]代表容量为i所能装入物品的最大价值

package woek1;

import java.util.Scanner;

public class pack0_1 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int v =sc.nextInt();
		int[] weight = new int[n];
		int[] value = new int[n];
        
		for(int i = 0;i<n;i++) {
			weight[i] = sc.nextInt();
			value[i] = sc.nextInt();
		}
        
		int[] dp = new int[v+1];
		for(int i = 1;i<=n;i++)
			//注意下标问题;
			for(int j = v;j>=weight[i-1];j--) {
				dp[j] = Math.max(dp[j], dp[j-weight[i-1]]+value[i-1]);
			}
		System.out.println(dp[v]);
	}
}

完全背包

和0-1背包基本类似,但状态方程变为dp[i][j] = Math.max(dp[i-1][j],dp[i][j-weight[i]]+value[i];

package woek1;

import java.util.Scanner;

public class completePack {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int v =sc.nextInt();
		int[] weight = new int[n];
		int[] value = new int[n];
		
		
		for(int i = 0;i<n;i++) {
			weight[i] = sc.nextInt();
			value[i] = sc.nextInt();
		}
		int[][] dp = new int[n+1][v+1];
		for(int i = 1;i<=n;i++)
			for(int j = 1;j<=v;j++) {
				if(j>=weight[i-1])
					dp[i][j] = Math.max(dp[i-1][j], dp[i][j-weight[i-1]]+value[i-1]);
				else 
					dp[i][j] = dp[i-1][j];
			}
		
		System.out.println(dp[n][v]);
	}
}

多重背包

和0-1背包类似,只不过多个数量限制,现在加一个循环,对数量合适的,选出最大的物品价值;

package woek1;

import java.util.Scanner;

public class completePack {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int v =sc.nextInt();
		int[] weight = new int[n];
		int[] value = new int[n];
		int[] num = new int[n];
		
		
		for(int i = 0;i<n;i++) {
			weight[i] = sc.nextInt();
			value[i] = sc.nextInt();
			num[i] = sc.nextInt();
		}
		int[][] dp = new int[n+1][v+1];
		
		for(int i = 1;i<=n;i++)
			for(int j =1;j<=v;j++) {
				if(weight[i-1] > j)
					dp[i][j] = dp[i-1][j];
				else {
					//求出符合条件的该物品数量最大值,进行循环求解
					int maxV = Math.min(num[i-1], j/weight[i-1]);
					for(int k = 0;k<=maxV;k++) {
						dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-k*weight[i-1]]+k*value[i-1]);
					}
				}
			}

        System.out.println(dp[n][v]);
		
	}
}

如有错误,欢迎指教;