01背包问题:
有一个背包它可以背n单位重量的物品,有几种物品它们的重量分别为1,2,3个单位,它们对应的权重分别为1500,2000,3000,求该背包怎样放物品才能使权重最大(一种物品只能放一次)
思路:
如下图用二维数组 v[i][j]代表i种物品在能负重j的背包里面的最大权重,且v[i][0]当背包负重为0时,背包权重为0,v[0][j]当物品个数为0时背包权重为0,
物品的重量
int[] w = {1, 2, 3};
物品的权重
int[] val= {1500, 2000, 3000};
1.判断背包的可承受重量和物品重量之间的关系,如果背包可承受重量小于当前添加待添加进来的物品则不能添加
if (j < w[i- 1]) {
v[i][j]=v[i-1][j];
}
2.如果背包可承受重量大于当前添加待添加进来的物品分两种情况
(1)v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]
待添加物品添加进来然后在背包剩下的重量范围类添加前面几种物品的权值大于该物品不添加进来之前的权重
则 这时权值就为该物品加入后的权值;并用path[i][j] = 1来记录操作,后面用于打印操作
(2)
待添加物品添加进来然后在背包剩下的重量范围类添加前面几种物品的权值小于等于该物品不添加进来之前的权重
则这时权值就为该物品加入前的权值
if (v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]) {
v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
path[i][j] = 1;
} else {
v[i][j] =v[i-1][j];
}
3.根据path[][]数组来打印操作
因为要输出权值最大的组合所以应该从后往前打印数组
int i=path.length-1;
int j=path[0].length-1;
while (i > 0 && j > 0) {
if (path[i][j] == 1) {
System.out.println("第"+i+"个物品被加入背包");
//j必须要减去当前待添加物品的权值才能得到背包余下的空间
j-=w[i-1];
}
//是因为i--可以用待插入物品前的任意物品进行组合弥补背包剩余空间
i--;
}
java代码实现:
package com.yg.algorithm;/*
@date 2020/3/17 14:48
动态规划解决01背包问题
*/
import java.util.Arrays;
public class knapsack01 {
public static void main(String[] args) {
//物品的重量
int[] w = {1, 2, 3};
//物品的权重
int[] val= {1500, 2000, 3000};
//代表书包的负重
int n=4;
//初始化数组
int v[][]=initArr(val.length,n);
//记录操作的数组
int [][]path=operatinsPath(w,val,v);
for (int[] arr : path) {
System.out.println(Arrays.toString(arr));
}
//打印操作
printOperator(path,w);
}
private static void printOperator(int[][] path,int []w) {
//因为要输出权值最大的组合所以应该从后往前
int i=path.length-1;
int j=path[0].length-1;
while (i > 0 && j > 0) {
if (path[i][j] == 1) {
System.out.println("第"+i+"个物品被加入背包");
//j必须要减去当前待添加物品的权值才能得到背包余下的空间
j-=w[i-1];
}
//是因为i--可以用待插入物品前的任意物品进行组合弥补背包剩余空间
i--;
}
}
private static int[][] operatinsPath(int []w, int []val,int[][]v) {
int [][]path=new int[val.length+1][v[0].length];
for (int i = 1; i < v.length; i++) {
for (int j = 1; j < v[0].length; j++) {
//判断背包的可承受重量和物品重量之间的关系,如果背包可承受重量小于当前添加待添加进来的物品则不能添加
if (j < w[i- 1]) {
v[i][j]=v[i-1][j];
} else {
if (v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]) {
v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
path[i][j] = 1;
} else {
v[i][j] =v[i-1][j];
}
}
}
}
return path;
}
private static int[][] initArr(int goodsKindOfNum, int knapsackWeight) {
//v[i][j]代表i种物品在能负重j的背包里面的最大权重
int [][]v=new int[goodsKindOfNum+1][knapsackWeight+1];
//v[i][0]当背包负重为0时,背包权重为0
for (int i = 0; i < v.length; i++)
v[i][0]=0;
//将v[0][j]当物品个数为0时背包权重为0
for (int j = 0; j < v[0].length; j++)
v[0][j]=0;
return v;
}
}