动态规划的学习中,我们对比了斐波那契数与动态规划的区别,在代码上我们进行递归操作能实现一个斐波那契数列:
public static long feiBo(int n) { if (n == 1 || n == 2) { return 1; } return feiBo(n - 1) + feiBo(n - 2); }
在使用时,我们很清楚的发现,在计算一些较大的位置的值时,其返回速度相当的满,原因在于在计算一个数时,他一直在计算每一个小的值,当所有的都计算玩之后才能返回结果。在学习时,我们将这段代码进行简单的修改就将这个性能各提上来了:
public static long feiBo(int n, long[] arr) { if (n == 1 || n == 2) { return 1; } if (arr[n - 1] == 0) { arr[n - 1] = feiBo(n - 1, arr) + feiBo(n - 2, arr); } return arr[n - 1]; }
对比于前面的代码,我们只进行了一个操作,就是用一个数组,进行保存每次计算完后的结果,在使用时,返回数组的下标就能快速的知道结果。
由此引出:动态规划的使用特点:
1、状态的保存
2、状态转移方程。
在动态规划中,经典的问题时背包问题,大致意思是:如何将背包空间利用起来,达到里面物品价值的最大化。简单举个例子 :
书包可装:5kg
物品 重量 价值
书 4 4
铅笔盒 2 6
零食 1 7
在几个物品中,我们对书包进行装配最大价值为:13元 ,是铅笔和加零食的组合。
这里是进行小数目的,我们可以很直观的判断最大价值,在大数量下,我们还是不能够简单找到。所以这就体现动态规划的价值,我们对每个位置的判断都进行记录,在进行比较时,我们要判断的是:
在该重量下的价值与
减去当前物品下的最大价值加上物品价值
进行比较,如果大于,就将大的值记录下来,方便之后的比较,就这样反复进行,最后我们能得到最大的价值。
代码实现为:
public static int cal(int[] wight, int[] value, int body) { int[][] maxValue = new int[value.length][body + 1]; //构建一个二维数组。 for (int i = value[0]; i <= body; i++) { maxValue[0][i] = value[0]; } for (int i = 1; i < value.length; i++) { for (int j = 1; j <= body; j++) { if (j < wight[i]) { maxValue[i][j] = maxValue[i - 1][j]; } else { maxValue[i][j] = Math.max(maxValue[i - 1][j], maxValue[i - 1][j - wight[i]] + value[i]); } } } for (int[] b : maxValue) { System.out.println(Arrays.toString(b)); } return maxValue[value.length - 1][body]; }
在进行了该算法之后,给我的启发是:
在进行大量的运算时,我们可以考虑将已经计算过的数进行保存,减少运算中的重复计算,提高程序的执行效率。