L2 递推 递归 分治

  • 递推以及一些应用
  • 简单的组合计数
  • 递归怎么写
  • 分治算法的实例分析

递推

  1.    f1–>fn:顺推法,对应递推
       fn–>f1:倒推法,对应递归
  2. 怎么解决递推的问题
        找到初始状态——找到递推公式——开始循环算即可
        自己找到递推关系!!!
  3. 用递推的方式求 Fibonacci 数列
f[0]=0;
f[1]=1;
    for(int i=2;i<=n;i++)
        f[i]=f[i-1]+f[i-2];
  1. 简单的排列组合:
    · 排列:从n个数中有序地选出m个数 A(n,m)=n!/(n-m)!;
      * 第一个数有n种取法,第二个数有n-1种取法…第m个数有(n-m+1)种取法
      * n*(n-1)(n-m-1)=n!/(n-m)!
      * 记为A(n,m)

    · 组合:从n个数中无序地选出m个数 C(n,m)=A(n,m)/m!;
      * 先有序地取m个数
      * 那么无序的m个数会被取到m! 次
      * 记为 C(n,m) = A(n,m)/m! = n! / [ m! (n-m)! ]

    · 组合数 C(n,m) 的递推式:C(n,m)=C(n-1,m)+C(n-1,m-1);
      * n个数,选m个,若没选最后一个,则为 C(n-1,m) // 成了从(n-1)个数中选m个了
      * 若选了最后一个数,则为 C(n-1,m-1) // 成了从(n-1)个数中选(m-1)个了
      * 因为是分步计数,所以相加

    · 可能有用的数学结论:
      C(n, 0) + C(n, 1) + … + C(n, n-1) + C(n, n) = 2n;
      C(n,0) + C(n,2) + … + C(n,n) = C(n,1) + C(n,3) + … + C(n,n-1) = 2n-1

递归

  1. · 为了求 f(n),必须先求 f(n-1);为了求 f(n-1),必须去求 f(n-2)…为了求 f(1),必须先求 f(0),而 f(0) 是已知的。
    · 这种定义函数的方式成为递归定义。
    · 一个递归定义必须是有终结的。终结条件称为递归边界。
    · 描述递归定义的函数或求解递归问题的过程称为递归算法。
  2. 递归算法一般是用在三个场合:
    · 数据的定义形式是递归的,如求 Fibonacci 数列问题;
    · 数据之间的逻辑关系(即数据结构)是递归的,如树、图等的定义和操作;
    · 某些问题虽然没有明显的递归关系或结构,但问题的解法是不断重复执行一种操作,只是问题规模由大化小,直至某个原操作(基本操作)就结束,如汉诺塔问题,这种问题使用递归思想来求解比其他方法更简单。
  3. 用递归的方式求 Fibonacci 数列
int F(int n)
{
    if(n==0) return 0;
    if(n==1) return 1;
    return F(n-1)+F(n-2);
}
  1. 但可以发现,对于一个值我们重复计算了多次,能不能把它记下来让它只计算一次呢?
    记忆化搜索
int f[maxn];
memset(f, -1, sizeof(f));
f[0]=0; f[1]=1;
int F(int n)
{
    if(f[n]!=-1) return f[n];
    else return f[n]=F(n-1)+F(n-2);
}  // 用一个数组记一下算过的数

分治

  1. 分治就是分而治之,把一个问题划分成若干个同样的小问题,然后各个击破。
    分支和递归思想是一脉相承的,大化小,小化了。
  2. 快速幂  时间复杂度 O(log2n) 即 O(logn)
     * 考虑计算 an
     * n是偶数,an = an/2 x an/2;n是奇数,an = a(n-1)/2 x a(n-1)/2 x a;
     * 这样每次只要计算 an/2 或 a(n-1)/2,n的规模减半
    例题:洛谷 P3414(数学+快速幂)
int pow_mod(unsigned long long a, unsigned long long n, int mod)
{
    if(n==0) return 1;
    if(n&1) return a*pow_mod(a, n-1, mod)%mod;  // b&1 即 b%2==1
    else
    {
        unsigned long long s=pow_mod(a, n/2, mod)%mod;
        return s*s%mod;
    }
}
  1. 归并排序基于分治思想
    · 归并排序一个很重要的应用就是求逆序对 
    · 逆序对:对于给定的一段正整数序列,逆序对就是序列中 a[ i ] > a[ j ] 且 i < j 的有序对
    · 做法:
    先考虑求 [ l, r ] 当中的逆序对个数,先求出中点m,然后将逆序对分为两种:跨越中点m的和不跨越中点m的
      - 对于不跨越中点的,把它看成 [ l, m ], [ m+1, l ] 两个子问题
      - 对于跨越中点的,考虑用归并排序的方法,在求逆序对的时候顺便排好序。逆序对的两个元素一个在左边的序列,一个在右边的序列。那么每次就是对于两个有序的序列统计,有多少个逆序对。用 cnt 记录逆序对的数量,用辅助数组记录排好顺序的数列。
    · 例题:洛谷 P1908

  2. 序列的分支问题有一个很常见的套路:
    · 把区间二分,先解决每个区间内的,再考虑跨越端点的
    · 例题:洛谷 P1115

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值