动态规划

转自:http://blog.csdn.net/a925907195/article/details/41313453

动态规划

一、基本概念

    动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。

二、基本思想与策略

    基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

    由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。

    与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)

 


三、适用的情况

能采用动态规划求解的问题的一般要具有3个性质:

    (1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。

    (2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。

   (3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势

 


四、求解的基本步骤(即先根据子决策倒推,倒推的目的是找到状态转移方程,然后编写代码时正推(遍历)去实现状态转移方程,从而实现最优解)

     动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。如图所示。动态规划的设计都有着一定的模式,一般要经历以下几个步骤。

    初始状态→│决策1│→│决策2│→…→│决策n│→结束状态

                      图1 动态规划决策过程示意图

    (1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。

    (2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。

    (3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程

    (4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。

    一般,只要解决问题的阶段状态状态转移决策确定了,就可以写出状态转移方程(包括边界条件)。

实际应用中可以按以下几个简化的步骤进行设计:

    (1)分析最优解的性质,并刻画其结构特征。

    (2)递归的定义最优解。

    (3)以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值

    (4)根据计算最优值时得到的信息,构造问题的最优解

 


五、算法实现的说明

    动态规划的主要难点在于理论上的设计,也就是上面4个步骤的确定,一旦设计完成,实现部分就会非常简单。

     使用动态规划求解问题,最重要的就是确定动态规划三要素

    (1)问题的阶段 (2)每个阶段的状态

    (3)从前一个阶段转化到后一个阶段之间的递推关系

     递推关系必须是从次小的问题开始到较大的问题之间的转化,从这个角度来说,动态规划往往可以用递归程序来实现,不过因为递推可以充分利用前面保存的子问题的解来减少重复计算,所以对于大规模问题来说,有递归不可比拟的优势,这也是动态规划算法的核心之处

    确定了动态规划的这三要素,整个求解过程就可以用一个最优决策表来描述最优决策表是一个二维表,其中行表示决策的阶段,列表示问题状态,表格需要填写的数据一般对应此问题的在某个阶段某个状态下的最优值(如最短路径,最长公共子序列,最大价值等),填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,最后根据整个表格的数据通过简单的取舍或者运算求得问题的最优解。

          f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}

 


六、动态规划算法基本框

代码

  
  
1 for(j=1; j<=m; j=j+1) // 第一个阶段 2   xn[j] = 复制代码初始值;
3 4  for(i=n-1; i>=1; i=i-1)// 其他n-1个阶段 5   for(j=1; j>=f(i); j=j+1)//f(i)与i有关的表达式 6 xi[j]=j=max(或min){g(xi-1[j1:j2]), ......, g(xi-1[jk:jk+1])}; 8 9 t = g(x1[j1:j2]); // 由子问题的最优解求解整个问题的最优解的方案 10 11 print(x1[j1]); 12 13 for(i=2; i<=n-1; i=i+1 15 { 17 t = t-xi-1[ji]; 18 19 for(j=1; j>=f(i); j=j+1) 21 if(t=xi[ji]) 23 break; 25 }
复制代码

转自:http://www.cnblogs.com/liuzhen1995/archive/2017/02/26/6452519.html

最优二叉查找树(Java)

问题描述

在了解最优二叉查找树之前,我们必须先了解何为二叉查找树?

引用自百度百科一段讲解:

二叉排序树(Binary Sort Tree)又称二叉查找树Binary Search Tree),亦称二叉搜索树

二叉排序树或者是一棵空树,或者是具有下列性质的二叉树

1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;

2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;

3)左、右子树也分别为二叉排序树;

在二叉查找树的基础上,引出了一个最优二叉查找树的问题:它在查找树中所有节点的平均键值比较次数是最低的。PS:如若对于最优二叉查找树的定义理解还是有点模糊,可以参考本文最后给出的参考资料中的链接)

 


解决方案

本文具体编码思想参考自《算法设计与分析基础》第三版,具体如下(PS:对于文中的具体思想,楼主自己是前后看了三四遍才整明白其具体思想,竟无语吟噎......,如若对于下面贴出的书中介绍无法理解,可以参考文末给出的参考资料的链接中,一位网友的博客讲解哦):

 

 

具体代码如下:

复制代码
package com.liuzhen.chapter8;

public class OptimalBST {
    /*
     * 参数P:表示1~n个节点的查找概率。其中P[0] = 0,无意义
     * 函数功能:返回在最优BST中查找的平均比较次数主表C[][],以及最优BST中子树的根表R
     */
    public void getBestTree(double[] P) {
        int lenP = P.length;
        double[][] C = new double[lenP+1][lenP];   //保存最有BST的成功查找的平均比较次数
        int[][] R = new int[lenP+1][lenP];   //保存最优BST中子树的根表R
        for(int i = 1;i < lenP;i++) {
            C[i][i] = P[i];
            R[i][i] = i;
        }
        
        for(int d = 1;d < lenP-1;d++) {
            for(int i = 1;i < lenP-d;i++) {
                int j = i + d;
                double minval = Double.MAX_VALUE;     //以double类型的最大值,表示minval趋向无穷大
                int kmin = 0;
                for(int k = i;k <= j;k++) {
                    if(C[i][k-1] + C[k+1][j] < minval) {
                        minval = C[i][k-1] + C[k+1][j];
                        kmin = k;
                    }
                }
                R[i][j] = kmin;
                double sum = P[i];
                for(int s = i+1;s <= j;s++)
                    sum += P[s];
                C[i][j] = minval + sum;
            }
        }
        
        System.out.println("在最优BST中查找的平均比较次数依次为:");
        for(int i = 1;i < C.length;i++) {
            for(int j = 0;j < C[0].length;j++)
                System.out.printf("%.1f\t",C[i][j]);
            System.out.println();
        }
        
        System.out.println("在最优BST中子树的根表R为:");
        for(int i = 1;i < R.length;i++) {
            for(int j = 0;j < R[0].length;j++)
                System.out.print(R[i][j]+"\t");
            System.out.println();
        }
    }
    
    public static void main(String[] args) {
        OptimalBST test = new OptimalBST();
        double[] P = {0,0.1,0.2,0.4,0.3};
        test.getBestTree(P);
    }
    
}
复制代码

运行结果:

复制代码
在最优BST中查找的平均比较次数依次为:
0.0    0.1    0.4    1.1    1.7    
0.0    0.0    0.2    0.8    1.4    
0.0    0.0    0.0    0.4    1.0    
0.0    0.0    0.0    0.0    0.3    
0.0    0.0    0.0    0.0    0.0    
在最优BST中子树的根表R为:
0    1    2    3    3    
0    0    2    3    3    
0    0    0    3    3    
0    0    0    0    4    
0    0    0    0    0    
复制代码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值