动态规划算法

基本介绍

在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。因此各个阶段决策的选取不能任意确定,它依赖于当前面临的状态,又影响以后的发展。当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线.这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题称为多阶段决策问题。在多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,称这种解决多阶段决策最优化的过程为动态规划方法 。
1)动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步获取最优解的外理筒法。
2)与分治算法不同的是适合于用动态规划求解的问题,经分解得到的子问题是下一个子阶段的基础。
3)动态规划可以通过填表的方式来逐步推进,得到最优解。

局限性

动态规划对于解决多阶段决策问题的效果是明显的,但是动态规划也有一定的局限性。首先,它没有统一的处理方法,必须根据问题的各种性质并结合一定的技巧来处理;另外当变量的维数增大时,总的计算量及存贮量急剧增大。因而,受计算机的存贮量及计算速度的限制,当今的计算机仍不能用动态规划方法来解决较大规模的问题,这就是“维数障碍”。

案例(背包问题)

有一个背包,容量为4磅,现有如下物品

1)要求达到的目标为装入的背包的总价值最大,并且重量不超出
2)要求装入的物品不能重复

图解

代码

public class KnapsackProblem {
  public static void main(String[] args) {
    //每个物品的重量
    int[] weight = {1,4,3};
    //每个物品的价格
    int[] money = {1000,3000,2500};
    //背包的容量
    int capacity = 4;
    //物品的个数
    int count = money.length;
    int[][] arr = new int[count + 1][capacity + 1];
    //记录放入商品的情况
    int[][] result = new int[count + 1][capacity + 1];
    //初始化第一行和第一列为0,可以省略
    //初始化第一行
    Arrays.fill(arr[0], 0);
    //初始化第一列
    for (int i = 0; i < arr.length; i++) {
      arr[0][i] = 0;
    }
    //动态规划处理,从第二行开始,跳过0
    for (int i = 1;i < arr.length; i++) {
      for (int j = 1; j < arr[0].length; j++) {
        if (weight[i - 1] > j) {  //如果第 i 个物品的重量大于背包容量为j,就采用背包容量为j时上一个物品的方案
          arr[i][j] = arr[i - 1][j];
        } else {
          if (arr[i - 1][j] < money[i - 1] + arr[i - 1][j - weight[i - 1]]) {
            //看一下放入第 i 个物品后剩余的背包容量的方案的价值加起来有没有背包容量为j时第i - 1个物品的方案的价值高
            arr[i][j] = money[i - 1] + arr[i - 1][j - weight[i - 1]];
            //把当前的情况记录到result
            result[i][j] = 1;
          } else {
            //否则就采用背包容量为j时第i - 1个物品的方案
            arr[i][j] = arr[i - 1][j];
          }
        }
      }
    }
    //输出价格表
    for (int[] ints : arr) {
      for (int j = 0; j < arr[0].length; j++) {
        System.out.print(ints[j] + "\t");
      }
      System.out.println();
    }
    //输出存入的物品,为了避免重复的存放记录,倒着找
    int i = arr.length - 1;   //行的最大下标
    int j = arr[0].length - 1;  //列的最大下标
    while (i > 0 && j > 0) {
      if (result[i][j] == 1) {
        System.out.printf("第%d个物品放入到背包\n",i);
        j -= weight[i - 1];
      }
      i--;
    }
  }
}

posted @ 2021-10-11 22:35  翻蹄亮掌一皮鞋  阅读(299)  评论(0)    收藏  举报