动态规划(一)钢条切割

简介

什么是动态规划

答:动态规划与分治法相似,都是通过组合子问题的解来求解原问题。他们之间的不同是,分治法将问题划分为互不相交的子问题,而动态规划应用于子问题重合的情况。使用分治法求解子问题重合的问题,会做许多不必要的工作,动态规划将已经求解的子问题保存到一张表格中,从而避免了反复求解重合子问题的情况。

动态规划常用来解决什么问题

答:最优化问题。最优化问题可以有很多可行解,每个解都有一个值,我们希望寻找具有最优值的解,最大或最小。我们称这样的解是问题的一个最优解(最优解可以有多个)。

设计动态规划算法的步骤

  1. 刻画一个最优解的结构特征;
  2. 递归的定义最优解;
  3. 计算最优解的值,通常采用自底向上的方法;
  4. 利用计算出的信息构造最优解;

问题

分析

从算法的角度来思考,我们如果要解决一个问题,只需要把这个问题的所有可能都列举出来。通过来检查每一种情况,来计算出一个最优的解。我们如何来穷举出所有的可能呢?

我们从钢条的最左端开始,在钢条长度为1的位置切割,那么问题的解即是r(n) = p[1] + r(n-1),我们看到问题的规模减小了,我们可以递归的解决子问题r(n-1)。一般的,r(n) = p[i] + r(n-i),i = 1,2,... n。

代码

/**
     * 递归解法
     * @param p
     * @param n
     * @return
     */
    public static int cut_rod(int[] p, int n){
        if(n == 0) return 0;
        int q = Integer.MIN_VALUE;
        for (int i = 1; i <= n; i++) {
            q = Math.max(q, p[i] + cut_rod(p, n - i));
        }
        return q;
    }

递归的解法求解了很多不必要的子问题,而我们可以将求解过的子问题记录下来。当遇到子问题时只需从表格中查找,这样就避免买子问题的重复计算。

/**
     * 带备忘录的自顶向下递归解法
     * @param p
     * @param n
     * @return
     */
    public static int memoized_cut_rod(int[] p, int n){
        int[] r = new int[n + 1];
        for (int i = 0; i < r.length; i++) {
            r[i] = Integer.MIN_VALUE;
        }
        return memoized_cut_rod_aux(p, n, r);
    }

    public static int memoized_cut_rod_aux(int[] p, int n, int[] r){
        if(r[n] >= 0) return r[n];
        int q;
        if(n == 0){
            q = 0;
        }else {
            q = Integer.MIN_VALUE;
            for (int i = 1; i <= n; i++) {
                q = Math.max(q, p[i] + memoized_cut_rod_aux(p, n - i, r));
            }
        }
        r[n] = q;
        return q;
    }



/**
     * 自底向上的解法
     * @param p
     * @param n
     * @return
     */
    public static int bottom_up_cut_rod(int[] p, int n){
        int[] r = new int[n + 1];

        r[0] = 0;
        for (int i = 1; i <= n; i++) {
            int q = Integer.MIN_VALUE;
            for (int j = 1; j <= i; j++) {
                q = Math.max(q, p[j] + r[i - j]);
            }
            r[i] = q;
        }

        return r[n];
    }

猜你喜欢

转载自www.cnblogs.com/xucoding/p/12183253.html