当前位置:   article > 正文

算法——动态规划(DP)_算法dp的四个步骤

算法dp的四个步骤

动态规划问题,大致可以通过以下四部分进行解决:

  • 划分阶段:按照问题的时间或空间特征,把问题分为若干个子阶段。(划分后的子阶段一定要是有序的或者是可排序的,否则问题就无法求解。)
  • 状态表示:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。(要满足无后效性。)
  • 状态转移:状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。
  • 确定边界:状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

只有当每个子问题都是离散的,不依赖于其他子问题时,动态规划才管用 。 

最大子序列

最长公共子序列(Longest Common Subsequence):两个序列公共子序列中的最长者,下面简称LCS,可能出现下面两种比较复杂的情况:
1.可能有多个

2.可能有歧义

步骤:

 

  • 首先判断两个字符是否相等,如果相等,根据上一个字符匹配的情况的最终值去生成该网格的值。
  • 如果不相等,根据网格的生成情况,获取该网格的前一个或者上一个的最终值进行比较大小后填充。

以此类推,得到状态转移公式: 

 

实现:

  1. /**
  2. * @Classname LargestSubsequence
  3. * @Description 动态规划——最大子序列
  4. * @Date 2019/8/12 14:03
  5. * @Created zzf
  6. */
  7. public class LargestSubsequence {
  8. public static void main(String[] args) {
  9. String str1 = "ADADVANTAGE";
  10. String str2 = "EDDUCATIONAL";
  11. int max = 0;
  12. char[] chars1 = str1.toCharArray();
  13. char[] chars2 = str2.toCharArray();
  14. //生成网格数组
  15. int[][] arrs = new int[chars1.length + 1][chars2.length + 1];
  16. //核心
  17. for (int i = 1; i <= chars1.length; i++) {
  18. for (int j = 1; j <= chars2.length; j++) {
  19. //如果字符匹配成功
  20. if (chars1[i - 1] == chars2[j - 1]) {
  21. //当前网格的值为上一层网格的前一个值+1。
  22. print_arr(arrs);
  23. arrs[i][j] = arrs[i - 1][j - 1] + 1;
  24. System.out.println("*********************************************");
  25. print_arr(arrs);
  26. System.out.println("*********************************************");
  27. } else {
  28. print_arr(arrs);
  29. //不相等时取左边或者上边两个比较大者
  30. arrs[i][j] = arrs[i - 1][j] > arrs[i][j - 1] ? arrs[i - 1][j] : arrs[i][j - 1];
  31. System.out.println("---------------------------------------------");
  32. print_arr(arrs);
  33. System.out.println("---------------------------------------------");
  34. }
  35. }
  36. }
  37. print_arr(arrs);
  38. System.out.println("最大公共序列值:" + arrs[chars1.length][chars2.length]);
  39. }
  40. public static void print_arr(int[][] arrs) {
  41. for (int i = 0; i < arrs.length; i++) {
  42. for (int j = 0; j < arrs[0].length; j++) {
  43. System.out.print(arrs[i][j] + " ");
  44. }
  45. System.out.println("");
  46. }
  47. }
  48. }

背包问题

步骤:

  • 首先判断该商品是否能够放进该空间大小的背包
  •      如果不能:获取上次的最优值
  •      如果能:判断上次的最优值与(本件商品的值)+最优值[(该大小的背包-本件商品的大小)],根据比较结果进行更新当前网格的最优值

以此类推,得到状态转移公式:  

实现:

  1. /**
  2. * @Classname Knapsack
  3. * @Description 背包问题
  4. * @Date 2019/8/12 15:02
  5. * @Created zzf
  6. */
  7. public class Knapsack {
  8. public static void main(String[] args) {
  9. //最大存储
  10. int MaxS = 13;
  11. int weight[] = {3, 4, 5, 6};
  12. int value[] = {4, 5, 6, 7};
  13. int number = weight.length;
  14. //生成网格
  15. int[][] V = new int[number + 1][MaxS + 1];
  16. //商品的下标
  17. for (int i = 1; i <= number; i++) {
  18. //背包可存储大小从1~MaxC最大格
  19. for (int j = 1; j <= MaxS; j++) {
  20. //判断该物品是否能够存储进该大小的背包
  21. if (weight[i - 1] <= j) {
  22. //判断上次存储在该大小的网格的价值是否比(该商品价格)+最优存储((该网格-该商品大小))要小
  23. if (V[i - 1][j] < V[i - 1][j - weight[i - 1]] + value[i - 1]) {
  24. //更新该网格的最优存储价值
  25. V[i][j] = V[i - 1][j - weight[i - 1]] + value[i - 1];
  26. } else {
  27. //说明此次存储的网格最优存储任然为上次存储的网格值(不更新)
  28. V[i][j] = V[i - 1][j];
  29. }
  30. } else {
  31. //不可以
  32. //该网格的最优存储为上一次存储的值
  33. V[i][j] = V[i - 1][j];
  34. }
  35. }
  36. }
  37. for (int i = 1; i <= number; i++) {
  38. for (int j = 1; j <= MaxS; j++) {
  39. System.out.print(V[i][j] + "\t");
  40. }
  41. System.out.println();
  42. }
  43. System.out.println("最存储是:" + V[number][MaxS]);
  44. }
  45. }

总结

  • 每种动态规划解决方案都涉及网格
  • 每个单元格都是一个子问题,而状态转移公式就是计算该单元格的最优解
  • 问题可分解成离散子问题时,可以用动态规划解决

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/927168
推荐阅读
相关标签
  

闽ICP备14008679号