🍀背包问题
描述:
# 有N件物品和一个容量是 V 的背包。每件物品只能使用一次。
第 i 件物品的体积是 vi,价值是 wi 。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
思考:
比如:
- 编号 1 2 3 4
- 体积 2 3 4 5
- 价值 3 4 5 6
表格a【i】【j】表示的是容量为j的背包装入前i个物品的最大价值。拿a【1】【3】和a【2】【3】举例,这里的a【2】【3】意思并不是在a【1】【3】的基础上考虑第2件物品,而应该理解为再拿一个空背包考虑前两件物品的情况。因此,如果空间不足以放入第2件,那么a【2】【3】=a【1】【3】;如果空间足够放入第2件,那么将背包容量减去第2件的容量,得j=3-3=0,而i=2-1等于1,找到a【1】【0】=0,那么物品2价值加上a【1】【0】得到总价值4,将4与a【1】【3】比较,取较大值即为a【2】【3】的值。 其他格子同理,如a【4】【8】,物品4价值6容量5,j=8-5=3,i=4-1=3,找到a【3】【3】值为4,6+4=10,10与a【3】【8】比较,10大,所以a【4】【8】=10。
实现:
public class _02_package {
static int[] weight = {0, 2, 3, 4, 5};
static int[] value = {0, 3, 4, 5, 6};
static int[][] dp = new int[5][9];
static int[] object = new int[5];
public static void Dynamic(){
for (int i = 1; i < 5; i++) {
for (int j = 1; j < 9; j++) {
if (weight[i] > j){
dp[i][j] = dp[i - 1][j];
}else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
}
}
// 回溯去找那些放入背包了
public static void Find(int i, int j){
if (i == 0){ //
for (int k = 0; k < 5; k++) {
System.out.println(object[k]);
}
return;
}
if (dp[i][j] == dp[i -1][j]){
object[i] = 0; // 未放入
Find(i-1, j);
}else if (dp[i][j] == (dp[i - 1][j - weight[i]] + value[i])){
object[i] = 1; // 已放入
Find(i-1, j - weight[i]);
}
}
public static void main(String[] args) {
dp[0][0] = 0;
Dynamic();
Find(4, 8);
}
}