博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态规划——递归写法和递推写法
阅读量:5039 次
发布时间:2019-06-12

本文共 2191 字,大约阅读时间需要 7 分钟。

一、什么是动态规划

  动态规划(DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子问题,通过综合子问题的最优解来得到原问题的最优解。

 

 

二、动态规划的递归写法

  以斐波那契(Fibonacci) 数列为例,斐波那契数列的定义为 F0=1,F1=1,Fn=Fn-1+Fn-2 (n≥2)。为了避免重复计算,可以开一个一维数组 dp,用以保存已经计算过的结果。代码如下:

1 int dp[maxn]; 2 // 斐波那契数列递归写法 3 int F(int n) { 4     if(n == 0 || n==1)    return 1;    // 递归边界 5     if(dp[n] != -1)    return dp[n];    // 已经计算过  6     else { 7         dp[n] = F(n-1) + F(n-2);    // 计算F(n),并保存  8         return dp[n];                // 返回 F(n) 结果  9     } 10 }

 

 

 

三、 动态规划的递归写法

  以经典的数塔问题为例,如下图所示,将一些数字排成数塔的形状,其中第一层有一个数字,第二层有两个数字……第 n 层有 n 个数字。现在要从第一层走到第 n 层,每次只能走向下一层连接的两个数字中的一个,问:最后将路径上所有数字相加后得到的和最大是多少?

  

  不妨令 dp[i][j] 表示从第 i 行第 j 个数字出发到达最底层的所有路径中能得到的最大和,在定义了这个数组后,dp[1][1] 就是最终想要的答案。

  如果想求出 dp[i][j],那么一定要先求出它的两个子问题“从位置 (i+1,j) 到达最底层的最大和 dp[i+1][j]”和“从位置 (i+1,j+1) 到达最底层的最大和 dp[i+1][j+1]”,即进行了一次决策:走左下还是右下。写成式子就是:

              dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + f[i][j]

  其中 f[i][j] 存放第 i 层的第 j 个数字。代码如下:

1 /* 2     动态规划的递推写法  3 */ 4  5 #include 
6 #include
7 #include
8 #include
9 #include
10 #include
11 12 #define maxn 100013 int f[maxn][maxn], dp[maxn][maxn]; 14 15 // 较大值 16 int max(int a, int b) {17 return a>b ? a : b;18 }19 20 int main() {21 int n;22 scanf("%d", &n);23 int i, j;24 for(i=1; i<=n; ++i) {25 for(j=1; j<=i; ++j) {26 scanf("%d", &f[i][j]); // 输入数塔 27 }28 }29 // 边界30 for(j=1; j<=n; ++j) {31 dp[n][j] = f[n][j];32 } 33 // 从第 n-1 层往上计算 dp[i][j]34 for(i=n-1; i>=1; --i) {35 for(j=1; j<=i; ++j) {36 dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + f[i][j]; 37 }38 } 39 printf("%d\n", dp[1][1]); // dp[1][1] 即为需要的答案 40 41 return 0;42 }

   

 

  下面指出两对概念的区别:

  1.  分治与动态规划。分治和动态规划都是将问题分解为子问题,然后合并子问题的解得到原问题的解。但是不同的是,分治法分解出的子问题是不重叠的,因此分治法解决的问题不拥有重叠子问题,而动态规划解决的问题拥有重叠子问题。另外,分治法解决的问题不一定是最优化问题,而动态规划解决的问题一定是最优化问题。

  2.  贪心与动态规划。贪心和动态规划都要求原问题必须拥有最优子结构。二者的区别在于,贪心法通过一种策略直接选择一个子问题去求解,没被选择的子问题就不去求解了,直接抛弃。也就是说,它总是只在上一步选择的基础上继续选择,因此整个过程以一种单链的流水方式进行。而动态规划总是从边界开始向上得到目标问题的解。也就是说,它总是会考虑所有子问题,并选择继承能得到最优结果的那个,对暂时没被继承的子问题,由于重叠子问题的存在,后期可能会再次考虑它们,因此还有机会成为全局最优的一部分,不需要放弃。    

 

转载于:https://www.cnblogs.com/coderJiebao/p/Algorithmofnotes26.html

你可能感兴趣的文章
code style--The Elements Of Programming Style
查看>>
Linux的正则练习
查看>>
团队冲刺02
查看>>
win7 - net 命令
查看>>
Java入门教程四(字符串处理)
查看>>
Windows Phone开发(23):启动器与选择器之CameraCaptureTask和PhotoChooserTask
查看>>
Linux 系统目录结构
查看>>
HealthKit开发教程之HealthKit的主要类型数据
查看>>
weblogic加载hibernate3时,ClassNotFoundException的解决方法
查看>>
我的软件工程之路(三)
查看>>
Nastya Studies Informatics CodeForces - 992B (大整数)
查看>>
Kilani and the Game CodeForces - 1105D (bfs)
查看>>
通过普通用户向各个节点服务器分发文件到各个目录
查看>>
SpringBoot swagger-ui.html 配置类继承 WebMvcConfigurationSupport 类后 请求404
查看>>
深入理解计算机系统(2.4)------整数的表示(无符号编码和补码编码)
查看>>
TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute
查看>>
01 Linear Regression with One Variable
查看>>
计算矩阵转置函数的步总数公式
查看>>
【Linux】- CentOS 防火墙iptables和firewall
查看>>
selenium安装及官方文档
查看>>