你来我们毒蛇帮总部干什么|

asdio

园龄:4年7个月粉丝:1关注:0

递推法

概述

递推法是一种根据递推关系进行问题求解的方法,常用来进行序列计算
根据初始条件,按照一定的规律逐项进行计算,直到得到结果

递推法正推和逆推

  1. 正推
    小规模问题的解递推到大规模问题的解
  2. 逆推
    大规模问题的解递推到小规模问题的解

例题

猴子吃桃

题目:猴子每天吃一半多一个的桃子,第十天只有一个桃子,问原来有多少个。
分析:

an={1n=10(an+1)×2n=9,8,7,6,...,1

int peach(int i){
    if(i==1)
        return 1;
    else
        return (peach(i-1)+1)*2;
}

斐波那契数列

题目:一对兔子放在围栏中,第二个月起,生一对兔子,新兔子下个月起生一对兔子,一年后有多少对兔子?

Fn={1n=1,2Fn1+Fn2n>2

int Fib(int n)
{
    if(n==1||n==2)
        return 1;
    else
        return Fib(n-1)+Fib(n-2);
}

错排问题

问题:n封信放进n个有地址的信封,全部放错的概率是?
分析:

信的数量 错排可能
1 0
2 1
n (n1)×Fn1+Fn2
int epp(int n){
    if(n==1) return 0;
    if(n==2) return 1;
    else return (n-1)*(epp(n-1)+epp(n-2));
}

整数拆分

问题:对于大于2的整数,用2的整数次幂进行拆分,有多少种拆分方式?
分析:
2->(1,1),(2)
3->(1,1,1),(1,2)
4->(1,1,1,1),(1,1,2),(2,2),(4)
5->(1,1,1,1,1),(1,1,1,2),(1,2,2),(4,1)
6->(1,1,1,1,1,1),(1,1,1,1,2),(1,1,2,2),(1,1,4),(2,2,2),(2,4)

分析可知,当n为奇数时,和n-1数量一样;当n为偶数时,为n/2中所有元素翻倍以及n-1所有的元素补充上1;

int div(int n){
    if(n==1){
        return 1;
    }
    else if(n%2==0){
        return div(n/2)+div(n-1);
    }
    else{
        return div(n-1);
    }
}

杨辉三角

问题:杨辉三角是二项式展开的系数的三角形,打印n阶杨辉三角

分析:每行的开头和结束都是1,其余为上一行同一列和前一列的和;

int main()
{
    int n;
    cin>>n;
    int a[n][n];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(j==0||j==i)
                a[i][j]=1;
            else
                a[i][j]=a[i-1][j-1]+a[i-1][j];
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

乘法结合问题

问题:在其前后次序不变的情况下,每次只对两个元素进行乘法,以括号决定乘的先后顺序,有多少种不同的相乘方式?

分析:
括号匹配问题,将左括号看作入栈,右括号看作出栈,题目既有多少出栈顺序。计算catalan数即可
img

catalan数的通项公式为

Cn=1n+1(2nn)=(2n)!(n+1)!n!,其中(ab)表示从a个元素中选取b个元素的组合数

递推公式为
Cn=k=0n1CkCn1k,n>0

long long catalan(int n) {
    // 如果n为0或1,返回1
    if (n == 0 || n == 1) {
        return 1;
    }
    // 否则,根据递推方程计算并返回结果
    long long result = 0;
    for (int k = 0; k < n; k++) {
        result += catalan(k) * catalan(n - 1 - k);
    }
    return result;
}

练习

    • 问题:6人参加会议,入场是随意把帽子挂在衣架上,走的时候顺手拿一顶,问拿对的概率
    • 分析:
      • 当5人拿对,只剩下一个帽子,此人拿对的概率是1;
      • 当4人拿对,只剩下2个帽子,2人拿对的概率是1/2;
      • ......
      • 第一人开始拿,此人拿对的概率是1/6
      • 通过递归计算
    • 实现
      double proba(double n){
          if(n==1) return 1;
          return (1/n)*proba(n-1);
      }
      
    • 问题:已知数列递推式:a1=1;a2i=ai+1,a2i+1=ai+ai+1,求第n项已经前n项最大值
    • 分析:
      • 使用数组实现递推,偶数位为i/2位的值+1,奇数为i/2位的值+i+1位的值;
      • 过程中记录最大值,运算结束后输出;
    • 实现:
      int sl(int n, int &max) {
          int num[n+1]={0};
          num[1] = 1;
          for (int i = 2; i <= n; i++) {
              if (i % 2 == 0) {
                  num[i] = num[i/2]+1;
              } else {
                  num[i] = num[i/2] + num[i/2+1];
              }
              if (num[i] > max) {
                  max = num[i];
              }
          }
          return num[n];
      }
      
    • 问题:一只猴子要爬上30级台阶,一步可以跳1级或三级台阶,共有多少种跳法?
    • 分析:若猴子当前在第n阶,则上一次可能在n-1阶或n-3阶,也就是说,到达第n阶的跳法f(n)=f(n-1)+f(n-3)
    • 实现:
      int mk(int n) {
          if (n==1||n==2)return 1;
          if (n==3)return 2;
          return mk(n-1)+mk(n-3);
      }
      
    • 问题:假设核反应堆有α和β两种粒子,每秒钟一个α可以分裂为3个β,一个β可以分裂为1个α和两个β。t=0时只有一个α,t秒的时候有多少α和多少β?
    • 分析:建立两个数组,依次计算
    • 实现:
      void particle(int t,int &alphas,int &betas) {
          int alpha[t]={0};
          int beta[t]={0};
          alpha[0]=1;
          for (int i = 1; i <= t; i++)
          {
              beta[i]=alpha[i-1]*3+beta[i-1]*2;
              alpha[i]=beta[i-1];
          }
          alphas=alpha[t];
          betas=beta[t];
      }
      
    • 问题:设x和y为非负整数,对集合{2x3y|x0,y0},求集合中小于整数n的元素个数,并求元素从小到大的排序的第m项元素
    • 分析:找到由1到n遍历,对2和3连续除,若结果为1,则表示该数为2和3的倍数(符合条件)
    • 实现:
    int main()
    {
        int n,m;
        while(cin>>n>>m)
        {
            int a[100001];
            int k=0;
            for(int i=1;i<=n;i++)
            {
                int temp=i;
                while(temp%2==0)
                    temp/=2;
                while(temp%3==0)
                    temp/=3;
                if(temp==1)
                    a[++k]=i;
            }
            cout<<k<<endl<<a[m]<<endl;
        }
    }
    
    • 题目:2×n的长方形,用若干个1×2的骨牌铺满,n=3时铺满方格共有3种方法,求对于给定的n,有多少种铺法?
      img
    • 分析:
      • n=1时,只有一种铺法,即f(1)=1
      • n=2时,有两种铺法,即f(2)=2
      • n>2时,我们可以考虑最右边一列的情况
        • 如果最右边一列是竖着放一个骨牌,则剩下的部分是一个2×(n1)的长方形方格,有f(n1)种铺法;
        • 如果最右边一列是横着放两个骨牌,则剩下的部分是一个2×(n2)的长方形方格,有f(n2)种铺法。
      • 因此,我们可以得到递推公式:f(n)=f(n1)+f(n2)
    • 实现:
          int domino(int n) {
              if (n==1)return 1;
              if (n==2)return 2;
              return domino(n-1)+domino(n-2);
          }
      

本文作者:asdio

本文链接:https://www.cnblogs.com/agitm/p/17168818.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   asdio  阅读(779)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起