03-动态规划

动态规划

动态规划法的求解过程:

  1. 划分子问题:将原问题分解为若干个子问题,每个子问题对应一个决策阶段,并且子问题之间具有重叠关系。
  2. 确定动态规划函数:根据子问题之间的重叠关系找到子问题满足的递推关系式(即动态规划函数),这是动态规划法的关键。
  3. 填写表格:设计表格,以自底向上的方式计算各个子问题的解并填表,实现动态规划过程。

动态规划算法的基本要素为最优子结构性质子问题重叠性质

一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,也称此问题满足最优性原理。

子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。

背包问题

背包问题是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,如何选择,才能使得物品的总价格最高。

三种背包:

  1. 01背包:物品只可以取一次
  2. 完全背包:物品可以取无限次
  3. 多重背包:物品可以取的次数有一个上限

01背包:设V(n,C)表示将n个物品装入容量为C的背包获得的最大价值,显然,初始子问题是把前面i个物品装入容量为0的背包和把0个物品装入容量为j的背包,得到的价值均为0,即:V(i,0)=V(0,j)=0V(i,j)在在决策x_i时,已确定了(x_1,...,x_{i-1}),则问题处于下列两种状态之一:

  1. 背包容量不足以装入物品i,则装入前i个物品得到的最大价值和装入前i-1个物品得到的最大价值是相同的,即x_i=0,背包不增加价值。

  2. 背包容量可以装入物品i,如果把第i个物品装入背包,则背包中物品的价值等于把前i-1个物品装入容量为j-w_i的背包中的价值加上第i个物品的价值v;如果第i个物品没有装入背包,则背包中物品的价值等于把前i-1个物品装入容量为j的背包中所取得的价值。显然,取二者中价值较大者作为把前i个物品装入容量为j的背包中的最优解。则得到如下递推式:
    V(i,j)= \left \{ \begin{array}\\ V(i-1,j) &j<w_i\\ max\{ V(i-1,j),V(i-1,j-w_{i})+Vi \} & j \ge w_i \end{array} \right.
    V(n,C)的值向前推,如果V(n,C)>V(n-1,C),表明第n个物品被装入背包,前n-1个物品被装入容量为C-w_n的背包中。

import java.util.Arrays;

public class DynamicProgramming {
    // 动态规划解决01背包
    public static int knapsack01(int[] weight, int[] value, int n, int capacity) {
        // 表格的行代表物品,列代表容量
        int[][] table = new int[n + 1][capacity + 1];
        // 初始化表格的第0列
        for (int c = 0; c <= n; c++)
            table[c][0] = 0;
        // 初始化表格的第0行
        for (int r = 0; r <= capacity; r++)
            table[0][r] = 0;
        // 填写表格
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= capacity; j++)
                if (j < weight[i]) // 此时的容量j,装不下物品i
                    // 此时价值为上一行这个容量时的价值
                    table[i][j] = table[i - 1][j];
                else // 此时的容量j,能装下物品i
                    table[i][j] = Math.max(table[i - 1][j], table[i - 1][j - weight[i]] + value[i]);
        }
        // 装入背包的物品:0未装入,1装入
        int[] loaded = new int[n + 1];
        for (int i = n, j = capacity; i > 0; i--)
            if (table[i][j] > table[i - 1][j]) {
                loaded[i] = 1;
                j = j - weight[i];
            } else {
                loaded[i] = 0;
            }
        System.out.println(Arrays.toString(loaded));
        return table[n][capacity];
    }

    public static void main(String[] args) {
        // 商品编号从1开始
        int[] weight = {0, 2, 12, 1, 1, 4};
        int[] value = {0, 2, 4, 2, 1, 10};
        // 物品数量
        int n = weight.length - 1;
        int capacity = 15;
        // [0, 1, 0, 1, 1, 1]
        // 15
        System.out.println(knapsack01(weight, value, n, capacity));
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容