常用算法之动态规划法

            上一篇博客我们讲了分治法,紧接着讲动态规划法:动态规划法和分治法类似,它也是将大问题分解成子问题求解,求最优解,不同的是,如果分解的子问题有很多是相同的,采用分治法相同的子问题会求解多次,很影响效率;动态规划法呢,它会保存已解决的子问题的答案,再有相同的子问题直接用保存的答案就行了,节省了很多计算时间。

      如一张图表示:

      

     

例:

解:我们先求F(5)的解,如下,以二叉树的结构表示

    通过二叉树,我们注意到,F(n)是通过计算它的两个重叠子问题 F(n-1)和F(n-2)的形式来表达的,所以,可以设计一张表填入n+1个F(n)的值。通过下面的表会发现:后一个数等于前面两个数的和。(这就是著名的斐波那契数)

所以,使用动态规划法的情况,对于一个问题具有的性质可以总结为:最优子结构,重叠子问题

适用情况:

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

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

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

 应用实例:

<span style="font-size:14px;">  public class CoinsChange {
        /**
         * 硬币找零:动态规划算法
         *
         * @param values
         *            :保存每一种硬币的币值的数组
         * @param valueKinds
         *            :币值不同的硬币种类数量,即coinValue[]数组的大小
         * @param money
         *            :需要找零的面值
         * @param coinsUsed
         *            :保存面值为i的纸币找零所需的最小硬币数
         */
        public static void makeChange(int[] values, int valueKinds, int money,
                int[] coinsUsed) {  

            coinsUsed[0] = 0;
            // 对每一分钱都找零,即保存子问题的解以备用,即填表
            for (int cents = 1; cents <= money; cents++) {  

                // 当用最小币值的硬币找零时,所需硬币数量最多
                int minCoins = cents;  

                // 遍历每一种面值的硬币,看是否可作为找零的其中之一
                for (int kind = 0; kind < valueKinds; kind++) {
                    // 若当前面值的硬币小于当前的cents则分解问题并查表
                    if (values[kind] <= cents) {
                        int temp = coinsUsed[cents - values[kind]] + 1;
                        if (temp < minCoins) {
                            minCoins = temp;
                        }
                    }
                }
                // 保存最小硬币数
                coinsUsed[cents] = minCoins;  

                System.out.println("面值为 " + (cents) + " 的最小硬币数 : "
                        + coinsUsed[cents]);
            }
        }  

        public static void main(String[] args) {  

            // 硬币面值预先已经按降序排列
            int[] coinValue = new int[] { 25, 21, 10, 5, 1 };
            // 需要找零的面值
            int money = 63;
            // 保存每一个面值找零所需的最小硬币数,0号单元舍弃不用,所以要多加1
            int[] coinsUsed = new int[money + 1];  

            makeChange(coinValue, coinValue.length, money, coinsUsed);
        }
    } </span>


时间: 2024-12-10 03:36:39

常用算法之动态规划法的相关文章

五大常用算法 之 动态规划法

一.基本概念     动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划.     动态规划是运筹学中用于求解决策过程中的最优化数学方法.当然,我们在这里关注的是作为一种算法设计技术,作为一种使用多阶段决策过程最优的通用方法.它是应用数学中用于解决某类最优化问题的重要工具.     如果问题是由交叠的子问题所构成,我们就可以用动态规划技术来解决它,一般来说,这样的子问题出现在对给定问题求解

常用算法之分治法与动态规划法

          之所以把这两种算法放到一起,是因为它们都是用来求最优解的问题,与贪心算法是不同的.但是这两种算法又有一些区别,下面来做解释:           分治,即分而治之,把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.                           上图用一个例子来解释如下:              当n>1时,想求得T(n),必须知道T(n-1),以此类推,所

五大常用算法——分治法,动态规划,回溯法,分支界限法,贪心算法

分治算法一.基本概念    在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)--     任何一个可以用计算机求解的问题所需的计算时间都与其规模有关.问题的规模越小,越容易直接求解,解题所需的计算时间也越少.例如,对于n个元素

php 常用算法和时间复杂度

本篇文章是对php中的常用算法以及时间复杂度进行了详细的分析介绍,需要的朋友参考下   按数量级递增排列,常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n),线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3) 复制代码 代码如下: //二分查找O(log2n) function erfen($a,$l,$h,$f){ if($l >$h){ return false;} $m = intval(($l+$h)/2); if ($a[$m] == $f){ r

php计算两个整数的最大公约数常用算法小结

 这篇文章主要介绍了php计算两个整数的最大公约数常用算法,实例总结了求最大公约数的三种常用方法,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了php计算两个整数的最大公约数常用算法.分享给大家供大家参考.具体如下:   代码如下: <?php //计时,返回秒 function microtime_float () { list( $usec , $sec ) = explode ( " " , microtime ()); return ((float)

【阿里云大学课程】机器学习入门:概念原理及常用算法

AlaphaGo与围棋界的较量,吸引了全世界的目光,也让大家见识到了机器学习与人工智能技术的强大之处.你是不是也想学机器学习了? 机器学习是人工智能的一个分支.人工智能的研究是从以"推理"为重点到以"知识"为重点,再到以"学习"为重点,一条自然.清晰的脉络.显然,机器学习是实现人工智能的一个途径,即以机器学习为手段解决人工智能中的问题. 在维基百科中,机器学习有下面几种定义: 机器学习是一门人工智能的科学,该领域的主要研究对象是人工智能,特别是如

JS实现的几个常用算法_javascript技巧

(1)数组去重 原理:定义一个对象obj,然后把数组元素作为obj的属性名,利用属性名是否重复进行判重 var unique = function(arr){ let obj = {}; let newArr = []; arr.forEach(function(x){ if(!obj[x]){ //如果对象中没有该元素对应的属性 obj[x] = true; newArr.push(x); } }); return newArr; } (2)使用快速排序算法对数组进行排序 这里面包括两种效果,

php计算两个整数的最大公约数常用算法小结_php技巧

本文实例讲述了php计算两个整数的最大公约数常用算法.分享给大家供大家参考.具体如下: 复制代码 代码如下: <?php //计时,返回秒 function  microtime_float () {     list( $usec ,  $sec ) =  explode ( " " ,  microtime ());     return ((float) $usec  + (float) $sec ); } /////////////////////////////////

轻松看懂机器学习十大常用算法

通过本篇文章可以对ML的常用算法有个常识性的认识,没有代码,没有复杂的理论推导,就是图解一下,知道这些算法是什么,它们是怎么应用的,例子主要是分类问题. 每个算法都看了好几个视频,挑出讲的最清晰明了有趣的,便于科普. 以后有时间再对单个算法做深入地解析. 今天的算法如下: 决策树 随机森林算法 逻辑回归 SVM 朴素贝叶斯 K最近邻算法 K均值算法 Adaboost 算法 神经网络 马尔可夫 1. 决策树 根据一些 feature 进行分类,每个节点提一个问题,通过判断,将数据分为两类,再继续提