动态规划DP学习

目录

 

1 DP理论

1.1 简介

1.2 基本思想

1.3 适用场景

1.4 其他

2 DP实例

2.1 杨辉三角

2.2矩阵取数问题

2.3 最长子串

2.4 揹包问题

3 dp总结


1 DP理论

1.1 简介

动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。

20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,

逐个求解,创立了解决这类过程优化问题的新方法——动态规划。整个动态规划,重点是找到转态转移方程。

做了实例之后发现,转移方程虽然是重点,却不是难点,状态转移的前提是知道啥是状态。不同的场景的建模方式不同,有些场景状态规律比较隐晦,或者说就是不太容易找到一个契合的定义。

1.2 基本思想

若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。

 

1.3 适用场景

动态规划常常适用于有重叠子问题和最优子结构性质的问题。

 

1.4 其他

DP和分治的区别:

共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解.

不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。

     动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。

 

2 DP实例

2.1 杨辉三角

略与2.2基本一样

 

2.2矩阵取数问题

一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值。例如:3 * 3的方格。

1 3 3

2 1 3

2 2 1

就是求到右下点的途径的路径的最大值。从递推的思想看,

右下角点的最大值等于上面和左边两个点的值的最大值加上右下角值,而左边或者上面的最大值亦是如此。因此可以将某个点的状态定义为到达该点路径累加和的最大值。

 

代码块

Java

  Scanner sc = new Scanner(System.in);
        int raw[][] = {{1,3,3},{2,1,3},{2,2,1}};
        int dp[][] = new int[3][3];
        int n = 3;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if(i == 0 && j==0)
                    dp[i][j] = raw[i][j];
                else if(i == 0 && j != 0){
                    dp[i][j] = dp[i][j-1] + raw[i][j];
                }else if(i != 0 && j == 0){
                    dp[i][j] = dp[i-1][j] + raw[i][j];
                }else {
                    dp[i][j] = Math.max(dp[i][j-1],dp[i-1][j]) + raw[i][j];
                }
            }
        }
        System.out.println(dp[n-1][n-1]);

// 测试代码功能没有问题,只是代码可能没必要有这么多的分支条件。 TODO优化条件分支

 

2.3 最长子串

状态定义:MaxSum[i]就表示A[0...i]以A[i]结尾的子数组最大和,那么MaxSum[i]就等于A[0...i-1]的最大和加上A[i]在和A[i]比较求最大值

状态转移方程:MaxSum[i] = Max{ MaxSum[i-1] + A[i], A[i]}

代码块

Java

public static void main(String[] args) {
// 最大子段和  状态Fi(i<=n)定义为考虑从零到i的序列其最大字段和为Fi, 则状态转义方程为 Fi = Fi +
        int [] MaxSum = new int[6];
        int array [] = {-5,5,5,5,-16,4};
        int length = array.length;
        MaxSum[0]=array[0];
        for(int i=1;i<length;i++){
            MaxSum[i]=Math.max(MaxSum[i-1]+array[i], array[i]);
        }
        for (int i = 0; i < MaxSum.length; i++) {
            System.out.println(MaxSum[i]);
        }
        //找到MaxSum中的最大值
        int maxSum=Integer.MIN_VALUE;
        for(int i=0;i<MaxSum.length;i++){
            if(MaxSum[i]>maxSum){
                maxSum=MaxSum[i];
            }
        }
        System.out.println(maxSum);
    }

 

2.4 揹包问题

揹包问题就没有以上两个问题,那么容易找到状态。

在N件物品取出若干件放在容量为W的揹包里,每件物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数)。求揹包能够容纳的最大价值。

 

3 dp总结

TODO 场景千千万万,但是是否有某种规律,能快速的针对给定场景分析出状态的定义???

最长非降序列长度的问题,其实都是单序列问题,其i都是等于前面的若干位置的子问题的某种计算

宝石问题和硬币问题感觉是同一个问题。宝石问题就是双序列问题,宝石问题有两个属性体积和价值两个序列,在限定体积的情况下,求价值最大值。

硬币问题相当于体积是定值,在限定价值的情况下,求最小体积?

感觉宝石问题是双序列,硬币由于体积固定是但序列问题?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章