题目描述
实现一个算法求解 01 背包问题。背包问题的介绍如下:
• 已知一个容量为 totalweight 的背包,有不同重量不同价值的物品,问怎样在背包容量限制下达到利益最大化。
• 01 背包问题要求每个物品只有一个,可以选择放入或者不放入背包。
背包问题求解方法的介绍如下:
• 用符号 Vi 表示第 i 个物品的价值,Wi 表示第 i 个物品的体积,Vi,j 表示当前背包容量为 j 时,前 i 个物品最佳组合对应的价值。
• 对于当前第 i 个商品,如果包的容量比该物品体积小,即 j<Wi。那么此时的价值与前 i−1 个的价值是一样的,即 Vi,j=Vi−1,j。
• 对于当前第 i 个商品,如果包的容量能够装下该物品,即 Wi≤j。此时需要判断装或者不装这个物品的价值对比,
选择使价值更大的情况,即 Vi,j=max(Vi+Vi−1,j−Wi,Vi−1,j)。
通过最优解回溯法找到解的组成:
• 当 Vi,j=Vi−1,j时,说明没有选择第 i 个物品。
• 当 Vi,j=Vi−1,j−Wi 时,说明装了第 i 个商品。
• 从 i,j 的最大值一直遍历到 i=0 ,则找到了所有解。
输入描述
第一行为两个数字 totalweight、N,均不超过 1000。totalweight 含义见题干,N 为物品数量。
接下来 N 行,每行两个数字 Wi、Vi,均不超过 1000。含义见题干。
输出描述
输出一行,为在背包容量限制下的最大化利益。
输入输出样例
8 5
3 4
5 5
1 2
2 1
2 3
输出
10
运行限制
• 最大运行时间:1s
• 最大运行内存: 256M
代码演示
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//在此输入您的代码...
int tw = scan.nextInt();//记录物品总重量
int n = scan.nextInt();
int[] w = new int[n+1];//记录第i个物品重量
int[] v = new int[n+1];//记录第i个物品的价值
for(int i = 1;i <= n;i++){//录入数据
w[i] = scan.nextInt();
v[i] = scan.nextInt();
}
int[][] dp = new int[tw+1][tw+1];//记录当背包总重量为i时,装入背包中物品的最大价值
for(int i = 1;i <= n;i++){//i表示第i个物品的重量
for(int j = 1;j <= tw;j++){//j表示背包总重量
if(j < w[i]){//当背包总重量为j时,物品的重量大于背包的总重量,则背包物品的总价值为:dp[i-1][j]
dp[i][j] = dp[i-1][j];
}
/**
* 当背包总重量为j时,物品的重量小于等于背包的总重量,则背包物品的总价值为: Math.max(v[i]+dp[i-1][j-w[i]],dp[i-1][j])
*
*/
if( j >= w[i]){
dp[i][j] = Math.max(v[i]+dp[i-1][j-w[i]],dp[i-1][j]);
}
}
}
//输出
System.out.println(dp[n][tw]);
scan.close();
}
}
以题目例子用二维表表示
最后的最大值根据判断条件:
dp[5][8] = dp[4][6] + 3 =10;
对于当前第 i 个商品,如果包的容量比该物品体积小,即 j < w[i]。那么此时的价值与前 i−1 个的价值是一样的,即 dp[i][j] = v [i-1][j]
对于当前第 i 个商品,如果包的容量能够装下该物品,即 w[i] ≤ j。此时需要判断装或者不装这个物品的价值对比,选择使价值更大的情况,即 dp[i][j] =Math.max(v[i] + dp[i-1][j-w[i]] , dp[i-1][j])
之后的完全背包、多重背包、分组背包都在此基础上演变