算法思想介绍
动态规划算法与分治算法相似都是采取了将大的问题换分为小的问题在求解,不通的是动态规划算法每一个小问题的求解都是建立在前一个小问题的基础上的,也就是说他们的小问题之间是不相互独立的。在利用动态规划解决问题的时候关键是找到算法的状态转移方程即当前的小问题是如何和前面的小问题产生关联的。
背包问题的解决是动态规划算法的一个经典应用,背包问题又可以分为01背包、完全背包。01背包问题指的是没见物品都中有一件,对于一个物品只有里两个状态,要么放入背包,要么不放入背包;完全背包指的是每件商品的个数都是无穷多的,只要能满足价值最大化,一件物品你就是可以放入任意多个的。两个算法都采用了一个二维数组来作为中间数据辅助我们计算出最终的结果,不同的是两个算法的状态转移方程是不同的,这也是我们算法的核心,亦是我们接下来代码解析注释的重点。
核心代码实现分析
在背包问题中我们对问题的分解是从两个维度上体现在,不断的增加背包中包含物品的种类,不断增大背包的容量。我们可以将它想成是一个二维的坐标体系,在这个分治的过程中我们通过一个中间的二维数组来记录这个对应坐标下的最优解。当前租表最优值的计算都可能用到前面已经计算出来的值,这一部分就是我们动态规划算法思想的体现。
01、完全背包问题代码实现
public class Knapsack {
public static void main(String[] args) {
int values[]={15,30,20};
int weights[] ={1,3,4};
System.out.println("01背包可装的最大价值为"+dynPlaKnapsack01(values,weights,4));
System.out.println("完全背包可装的最大价值为"+dynPlaKnapsackEntirely(values,weights,4));
}
public static int dynPlaKnapsackEntirely(int[] values,int[] weights,int capacity){
int elementCount = values.length;
int[][] dynPlaArrays = new int[elementCount+1][capacity+1];
int tempMaxValue = 0;
int tempValue = 0;
for (int i = 1; i <= elementCount; i++) {
for (int j = 1; j <= capacity; j++) {
for (int k = 0; k*weights[i-1]<=j; k++) {
tempValue = k*values[i-1]+dynPlaArrays[i-1][j-k*weights[i-1]];
if(tempMaxValue<tempValue){
tempMaxValue = tempValue;
}
}
dynPlaArrays[i][j]=tempMaxValue;
tempMaxValue =0;
}
}
return dynPlaArrays[elementCount][capacity];
}
public static int dynPlaKnapsack01(int [] values,int[] weights,int capacity){
int elementCount = values.length;
int[][] dynPlaArrays = new int[elementCount+1][capacity+1];
for (int i = 1; i <= elementCount; i++) {
//第一层的for循环控制的是元素
for (int j = 1; j <= capacity; j++) {
//第二层for循环控制的是背包的容量
if (weights[i-1]>j){
//当前元素的重量大于背包容量,元素不可以放入
dynPlaArrays[i][j] = dynPlaArrays[i-1][j];
}else{
//表示元素可以尝试放入,如果是可以放入的话就要看看放入前与放入后那个那个值更大
//放入后的值是新加入对的值+上一行中对应容量的最大值
dynPlaArrays[i][j] = Math.max(dynPlaArrays[i-1][j],(values[i-1]+dynPlaArrays[i-1][j-weights[i-1]]));
}
}
}
return dynPlaArrays[elementCount][capacity];
}
}