参考网址:https://blog.csdn.net/lvcoc/article/details/104167648

先不管动态规划,先看斐波那契数列

斐波那契数列:F1=Fn-1+Fn-2

分别用递归和非递归实现一下

递归

//递归
public int FibnacciA(int n)
{
  int res;
  if (n == 1 || n == 2)
  res = 1;
  else
  res = (FibnacciA(n - 1) + FibnacciA(n - 2));
  return res;
}
非递归

//非递归
public int FibnacciB(int n)
{
  List<int> f = new List<int>() { 0, 1, 1 };//斐波那契数列先初始化前3个特殊的
  if (n>2)
  {
    //n=3 计算1次 n=5 计算3次
    for (int i = 0; i < n-2; i++)
    {
      int fl= f.Count;
      f.Add(f[fl - 1] + f[fl - 2]);
    }
  }
  return f[n];
}
经过测试都是对的,但是重点不是这个,重点是运行时间

很明显非递归快的多,而且递归50或者100的时候,我直接卡死了。为啥

因为递归方法里有很多子问题的重复计算,而且数字越大,子问题重复越严重

而非递归的方法里子问题不会重复,而是存起来了

那么非递归的那个方法就可以称为动态规划(DP)

能够动态规划的问题需要两个关键点 1有递推式 2有重复子问题

钢条切割问题

某公司出售钢条,出售价格与钢条长度之间的关系如下表:

问题:现有一段长度为n的钢条和上面的价格表,求切割钢条方案,使得总收益最大。

举个栗子,下面列出的是0-10的最优收益

长度1的时候不用切就是1,长度2的时候可以切1+1,可以不切5,得到5,长度3的时候,首先不切是8,切1和2,2还可以切,但是2其实我们之前已经切过了,最优是5,所以不用继续考虑了,1和2就是1+5=6,最优是8,直接看长度8的时候,可以不切20,

可以切1和7,7之前也考虑过了是17,所以1和7就是1+18=19,最后发现最优是2和6,也就是5+17=22。

到这里其实我们发现这是一个递归的问题。那么我们需要一个递推式

递推式 R(n)=Max(P(n),R(1)+R(n-1),R(2)+R(n-2),.....,R(n-1)+R(1));

//递推式 R(n)=Max(P(n),R(1)+R(n-1),R(2)+R(n-2),.....,R(n-1)+R(1));
public int CutRodA(int n)
{
  int[] P = new int[] { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表
  int res = 0;
  if (n == 0)
  res= 0;
  else
  {
    res = P[n];//不切
    for (int i = 1; i < n; i++)
    {
      res = Mathf.Max(res,CutRodA(i)+CutRodA(n-i));
    }
  }
  return res;
}
测试一下

其实这个递推式还可以再简化,就是

从钢条的左边切割下长度为i的一段,只对右边剩下的一段继续进行切割,左边的不再切割

递推式就变成

public int CutRodB(int n)
{
  int[] P = new int[] { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表
  int res = 0;
  if (n == 0)
  res = 0;
  else
  {
    res = P[n];//不切
    //1<=i<=max
    for (int i = 1; i < n+1; i++)
    {
    res = Mathf.Max(res, P[i] + CutRodA(n - i));
    }
  }
  return res;
}
测试一下

但是 ,这两种方法都是自顶向下递归,会产生子问题重复,而且也是钢条越长,子问题重复越厉害

自顶向下从n开始,问题越分越细

也就是4需要3210,3需要210,越分越细

那么1有递推式,2有重复子问题,我们就可以用动态规划了,自底向上实现

//自底向上
public int CutRodC(int n)
{
  int[] P = new int[] { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//价格表
  List<int> r = new List<int>();//还是需要一个列表存子问题
  r.Add(0);//0长度收益0
  for (int i = 1; i < n + 1; i++)//自底向上从1开始存子问题
  {
    int res = 0;//每次需要重新计算收益
    //利用的是简化的递推式2,对于这个循环i就是n,j就是i
    for (int j = 1; j < i + 1; j++)
    {
      //本来r[i-j]也就是n-1,是需要递归,但是因为我们已经存过了,直接取就好了
     res = Mathf.Max(res,P[j]+r[i-j]);
    }
    r.Add(res);
  }
  return r[n];
}
我尽力注释了,但是还是可能有点绕,需要好好理解

测试一下他们的时间

动态规划明显快了很多

如果你想测试更长的钢条,你需要自己定制一个相应长度的价格表
————————————————
版权声明:本文为CSDN博主「lvcoc」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lvcoc/article/details/104167648

动态规划_C#的更多相关文章

  1. PJ可能会用到的动态规划选讲-学习笔记

    PJ可能会用到的动态规划选讲-学习笔记 by Pleiades_Antares 难度和速度全部都是按照普及组来定的咯 数位状压啥就先不讲了 这里主要提到的都是比较简单的DP 一道思维数学巧题(补昨天) ...

  2. 增强学习(三)----- MDP的动态规划解法

    上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...

  3. 简单动态规划-LeetCode198

    题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...

  4. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

  5. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  6. C#动态规划查找两个字符串最大子串

     //动态规划查找两个字符串最大子串         public static string lcs(string word1, string word2)         {            ...

  7. C#递归、动态规划计算斐波那契数列

    //递归         public static long recurFib(int num)         {             if (num < 2)              ...

  8. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  9. 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划

    [BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...

随机推荐

  1. QT从入门到入土(三)——文件的读写操作

     引言 文件的读写是很多应用程序具有的功能,甚至某些应用程序就是围绕着某一种格式文件的处 理而开发的,所以文件读写是应用程序开发的一个基本功能. Qt 提供了两种读写纯文本文件的基本方法: 用 QFi ...

  2. Kubernetes 1.13.3 部署 Prometheus+Grafana-7.5.2(最新版本踩坑)

    本教程直接在 Kubernetes 1.13.3 版本上安装 Prometheus 和 Grafana-7.5.2,至于它们的原理和概念就不再赘述,这里就直接开始操作. Git 下载相关 YAML 文 ...

  3. python03篇 字符串常用方法和文件操作(一)

    一.字符串常用方法 s1 = ' abcsfsfaadfdd ' s = s1.strip() print(s) print(len(s.strip())) print(s.count('a')) # ...

  4. 选择适合入门的自动化测试框架TestNG 基于Java语言的入门选择之一

    对于测试工程师新手来说,最痛苦的莫过于入门,其实只要入门3个月左右,对于自动化测试,所有的测试工程师除了喜爱,就是更爱.自动化测试工作,是从根本上解放人性,不用重复去完成鼠标的点点点,例如以下测试常常 ...

  5. 答读者问(1):非模式物种找marker;如何根据marker定义细胞类型

    下午花了两个小时回答读者的疑问,觉得可以记录下来,也许能帮到一部分人. 第一位读者做的是非模式物种的单细胞. 一开始以为是想问我非模式物种的marker基因在哪儿找,读者朋友也提到了blast 研究的 ...

  6. 前端开发入门到进阶第三集【js和jquery的执行时间与页面加载的关系】

    https://blog.csdn.net/u014179029/article/details/81603561 [原文链接]:https://www.cnblogs.com/eric-qin/p/ ...

  7. window对象之计时器--v客学院技术分享

    setTimeout()和setInterval()可以用来注册在指定的时间之后单次或者重复调用的函数.因为它们都是客户端JavaScript中重要的全局函数,所以定义为window对象的方法,但是作 ...

  8. (Opencv02)图片展示

    (Opencv02)图片展示 在程序里我们怎么把图片显示出来呢? 这里需要记一个自定义函数就好啦!  def cv_show(name, img):     cv2.imshow(name, img) ...

  9. centos的screen使用

    说明,screen 是一款安装在服务器,在单一终端窗口进行多任务切换的软件.好处在于.(1),使用多个窗口进行任务切换操作. 1,安装 (1),yum 安装 : yum install -y scre ...

  10. Gateway网关匹配规则

    Gateway匹配规则 重要概念 路由 route 断言 predicate 过滤器 fliter 一.时间匹配 在 after 时间之后的所有请求转发到 URI中的地址 gateway: disco ...