• 动态规划算法


    动态规划常被认为是递归的反向技术,所谓的递归算法是从顶部开始,把问题向下全部分解为小的问题进行解决,直到解决整个问题为止。而动态规划则是从底部开始,解决小的问题同时把它们合并形成大问题的一个完整解决方案。

    解决问题的递归算法经常是很优雅的,但是却是很低效的。尽管可能是优雅的计算机程序,但是C#语言编译器以及其他语言都不会把递归代码有效翻译成机器代码,并最终导致效率低下。

    许多用递归解决的编程问题可以使用动态规划进行重新编写。动态规划通常会使用缓存对象,将不同的子解决方案存储起来,将中间运算结果记录下来,从而大大提高了效率。实际上就是使用了空间换时间的办法。

    下面来看看一个递归算法的例子求斐波列数:

    static void Main(string[] args)
            {
                Program p = new Program();
                int n = 6;
                int res = p.Fib(n);
               
                Console.WriteLine("Fib_{0}={1},调用次数为 {2}", n, res, p.numCalls);
                Console.ReadKey();
            }
    
    private int numCalls = 0;
            private int Fib(int n)
            {
                numCalls++;
                Console.WriteLine("Fib调用 {0}", n);
                if(n<=1)
                {
                    return 1;
                }
                else
                {
                    return Fib(n - 1) + Fib(n - 2);
                }
            }

    这个是我们通常的做法,直接使用递归,简单而优雅。

    image

    计算结果显示,计算6的斐波列数,调用次数为25次。

    下面看看是动态规划的调用次数:

    static void Main(string[] args)
            {
                Program p = new Program();
                int n = 6;
                int res = p.FibL(n);
               
                Console.WriteLine("Fib_{0}={1},调用次数为 {2}", n, res, p.numCalls);
                Console.ReadKey();
            }
    
      private int FastFib(int n, Dictionary<int, int> memo)
            {
                numCalls++;
                Console.WriteLine("Fib调用 {0}", n);
                if(!memo.ContainsKey(n))
                {
                    memo.Add(n, FastFib(n - 1, memo) + FastFib(n - 2, memo));
                }
                return memo[n];
               
            }
    
            private int FibL(int n)
            {
                Dictionary<int, int> memo = new Dictionary<int, int>();
                memo.Add(0, 1);
                memo.Add(1, 1);
                return FastFib(n, memo);
            }

    image

    使用动态规划调用次数为11次。

    为了测试效率,我们把数值改了30,同时注释掉调用过程的打印代码

    image

    结果显示,动态规划比递归有很大的效率提高。

    递归的效率极低的,看看如下图中树就可以明确地知道递归算法的效率是多么的低

    image

    递归算法的问题在于递归过程中会重复计算太多的数值。如果编译器可以跟踪已经计算过的数值,那么这个函数就几乎不会如此低效了。利用动态规划技术来设计算法会比递归算法高效许多。

    使用动态规划技术设计算法从解决最简单的可解子问题开始入手,利用解决方案解决更加复杂的子问题直到接近整个问题为止。每个子问题的解决方案存储在缓存中,从而减少很多重复运算,大大提高效率。递归数越大,动态规划的效率相对递归来说,优势越明显。

  • 相关阅读:
    Docsify 如何在一个 MD 文件中嵌入另外一个文件
    集合与条件、循环语句
    字典(当索引不好用时)
    序列(列表、元组、字符串)
    变量、数据类型和运算符
    Python基础知识
    计算机基础知识
    Windows环境下Python2和Python3的安装
    操作系统基础
    计算机硬件基础知识
  • 原文地址:https://www.cnblogs.com/luoht/p/3100224.html
Copyright © 2020-2023  润新知