【算法概论】动态规划的主要属性及优质链接

1)重叠子问题 (Overlapping subproblems)

       像分治法一样,动态规划包含了对子问题的解决。动态规划主要用于不断地解决相同子问题。在动态规划中,子问题的计算解被存储在表中,使得这些不必重新计算。因此,当没有公共(重叠)子问题时,就不会使用动态规划。例如,二分搜索没有公共子问题。如果我们以斐波纳契数字的递归程序为例,有很多子问题会被反复解决。

/* simple recursive program for Fibonacci numbers */
int fib(int n)
{
   if ( n <= 1 )
      return n;
   return fib(n-1) + fib(n-2);
}

       fib(5)的递归树如下:


                          fib(5)
                     /             \
                fib(4)               fib(3)
             /      \                /     \
         fib(3)      fib(2)         fib(2)    fib(1)
        /     \        /    \       /    \
  fib(2)   fib(1)  fib(1) fib(0) fib(1) fib(0)
  /    \
fib(1) fib(0)

       我们可以看到函数 f(3) 被调用了2次。如果我们将存储 f(3) 的值,则不再计算它,我们可以重用旧的存储值。有以下两种不同的方法来存储值,以便可以重用这些值: 

       a)记忆(自上而下):

       用于问题的记忆程序类似于具有小修改的递归版本,它在计算解之前查找查找表。我们初始化一个所有初始值为 NULL 的查找数组。每当我们需要解决子问题时,我们首先查找查找表。如果预先计算的值存在,那么我们返回该值,否则我们计算值,并将结果放在查找表中,以便以后可以重复使用。

       b)制表(自下而上) :

       给定问题的制表程序以自下而上的方式构建表,并返回表中的最后一个条目。例如,对于相同的斐波纳契数,我们首先计算fib(0),fib(1),fib(2),fib(3)等等。因此,从字面上看,我们正在建立自下而上的子问题的解决方案。

       以下是第n斐波纳契数字的记忆版本:

/* C/C++ program for Memorized version for nth Fibonacci number */
#include<stdio.h>
#define NIL -1
#define MAX 100

int lookup[MAX];

/* Function to initialize NIL values in lookup table */
void _initialize()
{
    int i;
    for (i = 0; i < MAX; i++)
    {
        lookup[i] = NIL;
    }
    
    return;
}

/* function for nth Fibonacci number */
int fib(int n)
{
    if (lookup[n] == NIL)
    {
        if (n <= 1)
        {
            lookup[n] = n;
        }
        else
        {
            lookup[n] = fib(n-1) + fib(n-2);
        }
    }

    return lookup[n];
}

int main ()
{
    int n = 40;
    _initialize();
    printf("Fibonacci number is %d ", fib(n));

    return 0;
}

       以下是第n个斐波纳契数字的表格版本:

/* C program for Tabulated version */
#include<stdio.h>

int fib(int n)
{
    int f[n+1];
    f[0] = 0;
    f[1] = 1; 
    for (i = 2; i <= n; i++)
    {
        f[i] = f[i-1] + f[i-2];
    }

    return f[n];
}

int main ()
{
    int n = 9;
    printf("Fibonacci number is %d ", fib(n));

    return 0;
}

       输出:

Fibonacci number is 34

       参考:动态规划(篇1)重叠子问题

       还有一篇好的博文:动态规划-重叠子问题,这里面中英对比解释比较好(๑•̀ㅂ•́)و✧

2)最佳子结构 (Optimal substructure)

       一个问题的最优解一定包含它子问题的最优解。

 

练习参考:动态规划总结及题集整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值