动态规划的基本思想是,将原问题拆分为若干子问题,自底向上的求解。其总是充分利用重叠子问题,即通过每个子问题只解一次,把解保存在一个表中,巧妙的避免了子问题的重复求解。

递归方法,采用的是自顶向下的思想,拆分为若干子问题,但是造成了子问题的重复求解。

备忘录方法,采用的也是自顶向下的思想,但是该方法维护了一个记录子问题解的表,虽然填表动作的控制结构更像递归方法,但是的确避免了子问题的重复求解。

下面以字符串的相似度来展示一下各方法的特点:

动态规划

递归:略

备忘录:

[cpp] view plaincopy
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. using namespace std;
  5. const int N = 100;
  6. int dist[N][N];
  7. int minValue(int va, int vb, int vc)
  8. {
  9. int temp = va;
  10. if(vb < temp)
  11. temp = vb;
  12. if(vc < temp)
  13. temp = vc;
  14. return temp;
  15. }
  16. int distance(string strA, int pABegin, int pAEnd, string strB, int pBBegin, int pBEnd)
  17. {
  18. if(dist[pABegin][pBBegin]>=0)
  19. return dist[pABegin][pBBegin];
  20. if (pABegin > pAEnd)
  21. {
  22. if(pBBegin > pBEnd)
  23. dist[pABegin][pBBegin] = 0;
  24. else
  25. dist[pABegin][pBBegin] = pBEnd - pBBegin + 1;
  26. return dist[pABegin][pBBegin];
  27. }
  28. if (pBBegin > pBEnd)
  29. {
  30. if(pABegin > pAEnd)
  31. dist[pABegin][pBBegin] = 0;
  32. else
  33. dist[pABegin][pBBegin] = pAEnd - pBBegin + 1;
  34. return dist[pABegin][pBBegin];
  35. }
  36. if (strA[pABegin]==strB[pBBegin])
  37. {
  38. dist[pABegin][pBBegin] = distance(strA, pABegin+1, pAEnd, strB, pBBegin+1, pBEnd);
  39. return dist[pABegin][pBBegin];
  40. }
  41. else
  42. {
  43. int t1 = distance(strA, pABegin, pAEnd, strB, pBBegin+1, pBEnd);
  44. int t2 = distance(strA, pABegin+1, pAEnd, strB, pBBegin, pBEnd);
  45. int t3 = distance(strA, pABegin+1, pAEnd, strB, pBBegin+1, pBEnd);
  46. dist[pABegin][pBBegin] = minValue(t1, t2, t3)+1;
  47. return dist[pABegin][pBBegin];
  48. }
  49. }
  50. int main()
  51. {
  52. string A;
  53. string B;
  54. cin>>A;
  55. cin>>B;
  56. for (int i=0; i<N; i++)
  57. for(int j=0; j<N; j++)
  58. dist[i][j] = -1;
  59. cout<<distance(A, 0, A.length()-1, B, 0, B.length()-1);
  60. return 0;
  61. }

当n=0时,f(n) = 0

当n=1时,f(n) = 1

当n>1时,f(n) = f(n-1) + f(n-2)

递归算法:

[cpp] view plaincopy
  1. int fun(int n)
  2. {
  3. if(n <= 0)
  4. return 0;
  5. if(n == 1)
  6. return 1;
  7. return fun(n-1)+fun(n-2);
  8. }

备忘录方法:

[cpp] view plaincopy
  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100;
  4. int f[N];
  5. int fun(int n)
  6. {
  7. if(f[n]>=0)
  8. return f[n];
  9. if(n == 0)
  10. {
  11. f[0] = 0;
  12. cout<<"0"<<endl;
  13. return f[0];
  14. }
  15. if(n == 1)
  16. {
  17. f[1] = 1;
  18. cout<<"1"<<endl;
  19. return f[1];
  20. }
  21. cout<<n<<endl;
  22. f[n] = fun(n-1) + fun(n-2);
  23. return f[n];
  24. }
  25. int main()
  26. {
  27. for (int i=0; i<N; i++)
  28. f[i] = -1;
  29. cout<<fun(4);
  30. return 0;
  31. }

由于计算的时候只需要前两个数即可,所以代码还可以继续优化。但是对于上述的备忘录方法貌似不能继续进行空间优化了(不知道对否,如果理解的不对请不吝赐教~)。

但是对于下面的方法(就称为遍历方法吧),还是可以继续优化的。

[cpp] view plaincopy
  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100;
  4. int f[N];
  5. int main()
  6. {
  7. int n;
  8. cin>>n;
  9. for (int i=0; i<=n; i++)
  10. {
  11. if(i==0)
  12. f[i] = 0;
  13. else if(i==1)
  14. f[i] = 1;
  15. else
  16. f[i] = f[i-1] + f[i-2];
  17. }
  18. cout<<f[n];
  19. return 0;
  20. }

由于计算的时候只用了前两个数,所以没有必要使用数组。

[cpp] view plaincopy
  1. #include <iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. int n;
  6. cin>>n;
  7. int temp1, temp2, temp;
  8. for (int i=0; i<=n; i++)
  9. {
  10. if(i==0)
  11. temp1 = 0;
  12. else if(i==1)
  13. temp2 = 1;
  14. else
  15. {
  16. temp = temp1 + temp2;
  17. temp1 = temp2;
  18. temp2 = temp;
  19. }
  20. }
  21. cout<<temp;
  22. return 0;
  23. }

总结:从代码中可以看出来,遍历方法实际上是一种自底向上的方法,而备忘录方法是一种自顶向下的方法,也许正由于这个原因造成了备忘录方法无法进行空间优化。(待证)

 动态规划算法的基本要素: 
1  最优子结构性质
当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。
2  重叠子问题性质   
动态规划算法对每个问题只解一次,将其解保存在一个表格中,当再次需要解此问题时,用常数时间查看一下结果。因此,用动态规划算法通常只需要多项式时间。

备忘录方法:
•用一个表格来保存已解决的子问题的答案,用的时候查表即可。 
•采用的递归方式是自顶向下。
•控制结构与直接递归相同,区别在于备忘录方式为每个解过的子问题建立备忘录。 
•初始化为每个子问题的记录存入一个特殊的值,表示并未求解。在求解过程中,查看相应记录如果是特殊值,表示未求解,否则只要取出该子问题的解答即可。

备忘录方法与动态规划和递归的区别:

1、动态规划是自低向上 ,备忘录方法是自顶向下,递归是自顶向下

2、动态规划每个子问题都要解一次,但不会求解重复子问题;备忘录方法只解哪些确实需要解的子问题;递归方法每个子问题都要解一次,包括重复子问题• 。

动态规划解矩阵连乘问题

#include<iostream>
using namespace std;
void metrixchain(int n,int p[],int **s,int **m)
{
 for(int i=0;i<n;i++)
  m[i][i]=0;
 for(i=2;i<=n;i++)    //小于等于n
 {
  for(int j=0;j<n-i+1;j++) //横坐标
  { int k=j+i-1;   //纵坐标
  m[j][k]=m[j+1][k]+p[j]*p[k+1]*p[j+1];s[j][k]=j;
  for(int t=j+1;t<k;t++)
  {
   int u=m[j][t]+m[t+1][k]+p[j]*p[t+1]*p[k+1];
   if(u<m[j][k])
   {
    m[j][k]=u;s[j][k]=t;
   }
  }
  }
 }
}
void Traceback(int i, int j, int ** s)
{
 if (i==j||i==j-1) return;
 cout<<"divide after metrix "<<s[i][j]<<endl;
 Traceback(i, s[i][j],  s);
 Traceback(s[i][j]+1,j ,  s);
}

int main()
{
 int p[]={30,35,15,5,10,20,25};
 int **s=new int*[6];
 for(int i=0;i<6;i++)
  s[i]=new int[6];
 int **m=new int*[6];
 for( i=0;i<6;i++)
  m[i]=new int[6];
 metrixchain(6,p,s,m);
 for( i=0;i<6;i++)
 { for( int j=i;j<6;j++)
 cout<<m[i][j]<<" ";
 cout<<endl;
 }
 Traceback(0,5,s);
 return 0;

}

动态规划备忘录方法递归方法相关推荐

  1. 动态规划备忘录方法Java_动态规划和备忘录法的区别

    动态规划算法的基本要素:1最优子结构性质当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质.2重叠子问题性质动态规划算法对每个问题只解一次,将其解保存在一个表格中,当再次需要解此问题时 ...

  2. 备忘录方法与动态规划比较

     动态规划算法的基本要素:  1  最优子结构性质 当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质. 2  重叠子问题性质    动态规划算法对每个问题只解一次,将其解保存在一个表 ...

  3. 关于动态规划与备忘录方法的总结

    在基于划分子问题的基础上,衍生出两种优秀的方法--a. 动态规划  b. 备忘录算法 a. 动态规划的基础是最优子结构---若一个大问题可以划分成多个小问题,则在这多种划分中,必有一种划分,可使得作为 ...

  4. 【史上最详细】动态规划:矩阵连乘问题(C++实现,含备忘录方法)

    动态规划与分治法的异同: 相同点:其基本思想都是将待求解问题分解为若干子问题,先求解子问题,再结合这些子问题的解得到原问题的解. 差异点:与分治法不同的是,适合用动态规划法求解的问题经分解得到的子问题 ...

  5. 3n+1b 备忘录方法

    题目详情 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反复砍下去,最后一定在某一步得到n=1.卡拉兹在1950年的世界数学家大会上公布了这个猜 ...

  6. 动态规划问题解决方法及示例

    什么是动态规划 动态规划是求解决策过程最优化的数学方法.如果一个问题可以分解成若干个子问题,并且子问题之间还有重叠的更小的子问题,就可以考虑用动态规划来解决这个问题. 应用动态规划之前要分析能否把大问 ...

  7. nyoj 10 skiing(DAG上的最长路,备忘录方法)

    skiing 时间限制:3000 ms  |  内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑 ...

  8. 动态规划设计方法详解最长递增子序列

    很多读者反应,就算看了前文动态规划详解,了解了动态规划的套路,也不会写状态转移方程,没有思路,怎么办?本文就借助「最长递增子序列」来讲一种设计动态规划的通用技巧:数学归纳思想. 最长递增子序列(Lon ...

  9. 【递归 动态规划 备忘录法】Fibonacci数列(斐波那契数列)(C++)

    一.什么是Fibonacci数列 斐波那契数列指的是这样一个数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144- 用文字来说,就是从第3项开始,每一项都等于前两项 ...

最新文章

  1. Jsoup解析XML
  2. Think as developer, 从深入理解业务实现框架开始
  3. HBase基本操作命令整理
  4. Mysql更新关联子查询报错
  5. memcache/memcached/memcachedb 配置、安装
  6. Android 中 View的类关系图
  7. spring boot校园商铺系统 毕业设计源码论文+答辩PPT
  8. 长春甲骨文华育兴业|大数据社会的十三大具体应用场景
  9. 计算机协会副会职责,计算机协会规章制度解答.doc
  10. POI和jxl的比较
  11. 【服务器数据恢复】异常断电导致ESXI系统无法连接存储的数据恢复
  12. Weston中HDMI热拔插检测
  13. 74LS85 比较器 【数字电路】
  14. 有多久没有这么疯狂了?
  15. LSP是第一生产力 深夜开车,图片不够了怎么办?爪巴就完事了(爬虫爬取网页图片)
  16. omv 网站服务器,折腾篇 篇一:小白也爱折腾 篇一:N1全小白装NAS(omv)
  17. 亚马逊下架产品还能重新恢复吗?
  18. SD女仆–系统清洁工具v4.14.35 [专业版] [Mod Lite] [最新]
  19. 测水位,六种传感器都知道,算你牛!
  20. Python破解携程点击文字验证

热门文章

  1. 【Android 逆向】Android 逆向通用工具开发 ( Windows 平台静态库程序类型 | 编译逆向工具依赖的 Windows 平台静态库程序 )
  2. 【错误记录】Android Studio 编译报错 ( Could not determine java version from ‘11.0.8‘. | Android Studio 降级 )
  3. 【Flutter】Flutter 混合开发 ( Flutter 与 Native 通信 | Android 端实现 MethodChannel 通信 )
  4. MySQL 报 Can't create more than max_prepared_stmt_count statements
  5. 关于SQL视图的创建和使用方法
  6. Docker实战(一)之使用Docker镜像
  7. (五) 定点迭代法求根
  8. Unity Shader——Writing Surface Shaders(2)——Custom Lighting models in Surface Shaders
  9. ubuntu install fonts
  10. java的WebService实践(cxf)