算法之动态规划(递推求解一)

这篇博客主要讲的是动态规划入门,即动态规划的思想,并且再讲解动态规划的最简单的一个方法。

首先,什么是动态规划?

  动态规划是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)的方式去解决。其实就是分解问题,分而治之。可能这样说大家都不太理解,其实这个有点类似于数学中的递推公式。来举一个简单的例子,看下边这个题:

  N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式。

  这就是动态规划就简单的一个列子。拿到这个题,大家是不是都有点迷,这个到底怎么做?是不是没有思路,那么按照动态规划思想,我们可以先分析下问题,每次都有两种跳法,分别是一阶或者两阶,那么如果当前是第n个台阶,那么跳法是不是是(n-1)台阶的跳法数加上(n-2)台阶的跳法数?如果划算成公式是F(n) =  F(n-1)+F(n-2)。F(n)代表第n阶台阶的跳法的数量。

  这不就相当于找到了一个递推公式,然后来进行计算。具体的代码实现如下(采用的是非递归):

#include <stdio.h>    

int main()
{
        int i,N;
        long long a[90];
        while(~scanf("%d",&N))
        {
                a[1]=1;
                a[2]=2;
                for(i=3;i<=N;i++)
                        a[i]=a[i-1]+a[i-2];
                printf("%lld\n",a[N]);
        }    

        return 0;    

}   

下边再举一个列子来辅助理解:

  n封信放入n个信封,要求全部放错,共有多少种放法,记n个元素的错排总数为f(n)

  对于这个题,我们可以采用和上述一样的思路,我们是否要考虑下找一个类似的递推公式等来解决。思路如下:

  在任意一种错装方案中,假设n号信封里装的是k号信封的信,而n号信封里的信则装在m号信封里。我们按照k和m的等值与否将总的错装方式分为两类。  若k不等于m,交换n号信封和m号信封的信后,n号信封里装的恰好是对应的信,而m号信封中错装k号信封里的信,即除n号信封外其余n-1个信封 全部错装,其错装方式等于 F[n - 1],又由于m的n-1个可能取值,这类错装方式总数为(n - 1)* F[n - 1]。也可以理解为,在 n-1个信封错装的 F[n - 1]种方式的基础上,将n号信封所装的信与n - 1个信封中任意一个信封(共有 n-1 中选 择)所装的信做交换后,得到所有信封全部错装的方式数。另一种情况,若 k 等于 m,交换 n 号信封和 m 号信封的信后,n 号信封和 m 号信封里装的恰好是对应的信,这样除它们之外剩余的 n-2 个信封全部错装,其 错装方式为 F[n - 2],又由于 m 的 n-1 个取值,这类错装方式总数为(n - 1)* F[n - 2]。也可以理解为,在 n - 2 个信封全部错装的基础上,交换最后两个信封中的 信(n 号信封和 1 到 n-1 号信封中任意一个,共有 n-1 种选择),使所有的信封全部 错装的方式数。  综上所述,F[n] = (n - 1) * F[n - 1] + (n - 1) * F[n - 2]。这就是错排公式。

  具体代码如下:

#include <stdio.h>
Long long F[21]; //数值较大选用long long
int main () {
  F[1] = 0;
  F[2] = 1; //初始值
  for (int i = 3;i <= 20;i ++)
    F[i] = (i - 1) * F[i - 1] + (i - 1) * F[i - 2]; //递推求得数列每一个数字
  int n;
  while (scanf ("%d",&n) != EOF) {
    printf("%lld\n",F[n]); //输出
  }
  return 0;
}

  

  

时间: 2024-10-12 14:05:12

算法之动态规划(递推求解一)的相关文章

动态规划之递推求解

动态规划在B站上有个up主讲得不错,在此分享出来,如果对动态规划还比较懵逼的可以先去看看. https://www.bilibili.com/video/av16544031/?from=search&seid=11703697737879318733 https://www.bilibili.com/video/av18512769/?from=search&seid=6673249141547844536        利用递推解决问题,首先确定几个规模较小的问题答案.然后考虑如何由这

算法基础二 递推法

/*递推法*/ /*斐波那契数列 1 1 2 3 5 8 13..... f(n)?*/ /*递推法的特点是由前向后推算,因此注意起始条件,并在推算过程中保存结果供下一步推算使用~*/ #include<iostream> using namespace std; int f1(int n) { if (n < 3)return 1; else { int t1 = 1; int t2 = 1; for (int i = 2; i < n; i++) { int temp = t1

算法设计 之 递推法

递推法就是根据已知条件,分析推导出问题中的联系,然后一步一步进行推倒直至得到结果. 根据具体问题我们需要选择是正推还是逆推来解决问题. 下面先举一个递推中的经典例子,就是求兔子数量的问题: 现有一只一个月大的兔子,已知当兔子在第三个月大时每月就可以生下一只小兔子(好吧,就按兔子是无性繁殖的),求一年后兔子的总数量. 我们根据问题分析,发现可以把兔子分三类:一个月大.二个月大.三个或三个以上月大,列表分析: 月份 1月大 2月大 >=3月大 1 1 0 0 2 0 1 0 3 1 0 1 4 1

山区建小学(区间型动态规划,递推)

描述政府在某山区修建了一条道路,恰好穿越总共m个村庄的每个村庄一次,没有回路或交叉,任意两个村庄只能通过这条路来往.已知任意两个相邻的村庄之间的距离为di(为正整数),其中,0 < i < m.为了提高山区的文化素质,政府又决定从m个村中选择n个村建小学(设 0 < n < = m < 500 ).请根据给定的m.n以及所有相邻村庄的距离,选择在哪些村庄建小学,才使得所有村到最近小学的距离总和最小,计算最小值.输入第1行为m和n,其间用空格间隔第2行为(m-1) 个整数,依次

数的计数(noip2001,动态规划递推)

题目链接: 普通版: https://www.luogu.org/problemnew/show/P1028 数据加强版: https://www.luogu.org/problemnew/show/P2240 中间插一段,奇怪了,我明明想到的是最好的那种递推方法,结果写着写着忘记了,写成最差的递推方法 所以中间插一段被我遗忘的好方法 这个也是这题的书上的答案 #include<bits/stdc++.h> using namespace std; int a[1001]; int main(

[题解][SHOI2013]超级跳马 动态规划/递推式/矩阵快速幂优化

这道题... 让我见识了纪中的强大 这道题是来纪中第二天(7.2)做的,这么晚写题解是因为 我去学矩阵乘法啦啦啦啦啦对矩阵乘法一窍不通的童鞋戳链接啦 层层递推会TLE,正解矩阵快速幂 首先题意就是给你一个 n 行m 列 的格子图 一只马从棋盘的左上角跳到右下角.每一步它向右跳奇数列,且跳到本行或相邻行. 题意很简单暴力dp的思路也很简单但是数据很恶心虽然远古一点,但毕竟是省选题 1 ≤ n ≤ 50,2 ≤ m ≤ 10^9 不过还是给了我们一点提示:n这么小? 总之我们先找出转移式对于每一个点

Prob.2[动态规划+递推+划归思想的应用]POJ 1958 Strange Towers Of Hanoi Upd:2020.3.1

传送门:http://poj.org/problem?id=1958 汉诺塔:https://www.cnblogs.com/antineutrino/p/3334540.html 问题引入:这个在标准的三塔问题上又加了一维,我们先考虑三个塔是怎么计算的?可以具体地分成三个步骤: 1.假设A塔上有n个盘子,将A塔上n-1个盘子转移到B塔上. 2.将A塔上剩余的一个盘子转移到C塔上. 3.将B塔上剩余的n-1个盘子转移到C塔上 因为后转移的盘子小,上面n-1个盘子都能落在上面,2之后的C柱可以看成

[P1192]台阶问题 - 动态规划 - 递推

https://www.luogu.org/problemnew/show/P1192 题目描述 有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少1级),问到达第N级台阶有多少种不同方式. 输入输出格式 输入格式: 输入文件的仅包含两个正整数N,K. 输出格式: 输入文件stair.out仅包括1个正整数,为不同方式数,由于答案可能很大,你需要输出mod 100003后的结果. 输入输出样例 输入样例#1:复制 5 2 输出样例#1:复制 8 说明 对于20%的数据,有N ≤ 10

作业四 递推求解

记录点滴. 1 /* 2 2015.6 HT 3 ACM Work_4 4 5 */ 6 #include <iostream> 7 #include<algorithm> 8 using namespace std; 9 10 /* 11 超级楼梯 12 一楼梯共M级,刚开始在第一级,每次只能跨上一级或二级 13 要走上第M级,共有多少种走法? 14 输入每行包含一个整数M(1<=M<=40),表示楼梯的级数 15 16 直接构造一个40以内的斐波那契数列即可,f1=