应用场景:
一个已知容量为4的背包,有3种商品分别为A、B、C,不同的商品有不同的价格,且重量也不相等
商品 | 重量 | 价格 |
---|---|---|
A | 1 | 1500 |
B | 4 | 3000 |
C | 3 | 2000 |
问题1:如何存放商品到背包中,使得背包中的商品价值最大。(商品不能重复)
动态规划算法在这个应用中可以理解为:先求出背包容量为1的最优解,在这个基础上去尝试求出背包容量为2的最优解,……一直求出背包容量为4的解。
接下来用一张表格来说明:
容量 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
尝试放入A | 1500(A) | 1500(A) | 1500(A) | 1500(A) |
尝试放入B | 1500(A) | 1500(A) | 1500(A) | 3000(B) |
尝试放入C | 1500(A) | 1500(A) | 2000(C) | 2000(C)+1500(A) |
- 假设从A商品开始放入背包,得到容量为1的最优解为:【A】;再求容量为2时的最优解:【A】;由于不能存放相同的商品,容量为2、3、4时的解都为【A】
- 接下来在存放A的基础上存放商品B:容量为1、2、3时,都放不下B,所以就取之前的最优解【A】;当容量为4时,先放入B,发现容量已满,再与之前的最优解进行比较,得到【B】
- 接下来在存放C:容量为1、2时,放不下C,所以就取之前的最优解【A】;当容量为3时,先放入B,发现容量已满,与之前的最优解比较,得到【C】;容量为4时,放入C,剩余容量为1,所以加上剩余容量的最优解【A】,得到【C、A】与之前的最优解进行比较,得到【C、A】
总体来说是,计算当前解时,有剩余容量时加上剩余容量的最优解,得到当前解后,再比较之前算得的当前容量最优解,取最大的那个解
代码:
public class DynamicProgramming {
public static void main(String[] args) {
int bagWeight = 4;//背包可装的重量
char[] name = {'A','B','C'};//物品名称,例:name[0],为物品A
int[] weigth = {1,4,3};//物品重量,例weight[0],为物品A的重量
int[] val = {1500,3000,2000};//物品的价值,例val[0],为物品A的价值
//1、创建表,也就是二维数组
int proNum = name.length;//物品数量
int[][] vals = new int[proNum][bagWeight];//创建以物品数量为行,背包容量为列的二维数组
String[][] proNames = new String[proNum][bagWeight];//记录存放的物品
for(int i=0;i<vals.length;i++){//i表示name数组中索引为i的商品,i=0时物品为A
for(int j=0;j<vals[i].length;j++){//j表示容量为j+1
//vals[i][j] 表示有0~i种物品,在j+1的容量下存放最优解的价值
int w = j+1;//当前容量
String proName = "";
if (w>=weigth[i]){//当可以放下该物品时
int residue = w-weigth[i];//剩余容量
int v;//重新计算的值(不一定是最优解)
if(residue>0){
//如果有剩余容量,再加上剩余容量的最优解
if (i==0){//i==0时,没有最优解
v = val[i];
proName = proName+name[i];
}else{
//vals[i-1][residue-1]为0~i-1种物品时的剩余容量的最优解
v = val[i]+vals[i-1][residue-1];
proName = proName+name[i]+proNames[i-1][residue-1];
}
}else{
//没有剩余容量
v = val[i];
proName = proName+name[i];
}
//与最优解进行比较,得出最大值
if(i==0){ //i==0时,没有最优解
vals[i][j] = v;
proNames[i][j] = proName;
}else{ //vals[i-1][j]为当前容量的最优解
if(v>vals[i-1][j]){
vals[i][j] = v;
proNames[i][j] = proName;
}else{
vals[i][j] = vals[i-1][j];
proNames[i][j] = proNames[i-1][j];
}
}
}else{//放不下该物品时,取之前的当前容量最优解
if(i!=0){
vals[i][j]=vals[i-1][j];
proNames[i][j] = proNames[i-1][j];
}
}
}
}
printArr(vals);
printArr(proNames);
}
public static void printArr(int[][] arr){
for(int i = 0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+" ");
}
System.out.print('\n');
}
}
public static void printArr(String[][] arr){
for(int i = 0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+" ");
}
System.out.print('\n');
}
}
}
>>>
价值
1500 1500 1500 1500
1500 1500 1500 3000
1500 1500 2000 3500
物品
A A A A
A A A B
A A C CA
所以最优解为放【C、A】价值为3500