递推算法

递推算法:一般来说,递推算法的特征就是知道前一项、两项或者三项的值,并通过一定规律即可推出后面n个的值。


在山东理工OJ中,有以下几个有关递推的题目。

1243母牛的故事:

/*
    解题思路:
        第一年 1 头母牛 f[1] = 1;
        第二年 2 头母牛 f[2] = 2;
        第三年 3 头母牛 f[3] = 3;
        第四年 4 头母牛 f[4] = 4;
        f[n] = f[n-1] + 某一规律 
        第五年 6 头母牛 f[5] = f[4] + f[5-4+1];//由于第五年 此时第二年生的小牛也生了一个小牛 再加上最先的那头母牛 即f[2]
        第六年 8 头母牛 f[6] = f[5] + f[6-4+1];
        所以当n>4时通项为f[n] = f[n-1] + f[n - 4 +1];
*/
#include<iostream>
using namespace std;
int main(){
    long long res[55];
    res[1] = 1;
    res[2] = 2;
    res[3] = 3;
    res[4] = 4;
    for(int i = 5;i<=54;i++){
        res[i] = res[i-1] + res[i-4+1];
    }
    int n;
    while(cin>>n&&n){
        cout<<res[n]<<endl;
    }
    return 0;
}



2050王小二切饼:

/*
    解题思路
    n条直线分割平面 主要就是套取公式:n *(n+1)/2 +1 快
    一刀 2块
    两刀 4块
三刀 7块
当然也可以用递推公式得出 f[n] = f[n-1] +某一规律
所以某一规律 = f[n] - f[n-1] = (n+1) *n/2 +1 - (n-1)*n/2 -1 = n;
所以通项为 f[n ] = f[n-1] + n;


    */
#include<iostream>
using namespace std;
int main(){
    int n;
    while(cin>>n)
        cout<<n * (n+1)/2 +1<<endl;
    return 0;
    }


1018骨牌铺方格:

#include<iostream>
#include<stdio.h>
using namespace std;
long long a[52];
int main(){
int i,n;
a[1]=1;a[2]=2;
for(i=3;i<51;i++)
a[i]=a[i-1]+a[i-2];
while(scanf("%d",&n)!=EOF){
printf("%lld\n",a[n]);
}
return 0;
}


2173爬楼梯:

/*
    解题思路
        当 n = 3时 有三种可能性
        当 n = 1时 只有一种
        当 n = 2 时只有2两种
        可以看成序列长度为 n 的可以看成 由长度为n-1基础上加一步故有
        f[n-1]种
        也可以看成长度为n-2的基础上加一个两步的故有f[n-2]种
        所以f[n] = f[n-1] + f[n-2]
*/
#include<iostream>
using namespace std;
int main(){
    long long res[51];
    res[1] = 0;
    res[2] = 2;
    res[3] = 3;
    for(int i = 4;i<=50;i++)
        res[i] = res[i-1] + res[i-2];
    int n;
    while(cin>>n){
        cout<<res[n]<<endl;
    }
    return 0;
  }


1218养兔子:和母牛的故事雷同。



3460小银考呀考不过四级:

/*
    Fighting_小银考呀考不过四级
    解题思路
    其实可以把排n个座位看成长度为n的序列
    当序列长度为n 时 则可以分为两种情况
    第n位做人
        所以n-2和n-1位都不能做人了 即有f[n-3]种
        当第n位做人 所以前面n-3是可以不做人的而f[n-3]所表示
        的是前n-3个座位至少做一人 故还需要加上一种情况时前n-3
        都不做人即f[n-3] +1
    第n位不做人
        所以与第n-1位的派法一样即f[n-1]种
        所以通项为f[n] = f[n-1] + f[n-3] + 1;
*/
#include<iostream>
using namespace std;
int main(){
    long long res[91];
    res[1] = 1;
    res[2] = 2;
    res[3] = 3;
    res[0] =0;
    for(int i =4;i<=50;i++){
        res[i] = res[i-1] + res[i-3] +1;
    }
    int n;
    while(cin>>n){
        cout<<res[n]<<endl;
    }
    return 0;
    }


2058三国轶事——巴蜀之危:

/*
    Fighting_小银考呀考不过四级
    解题思路
    其实可以把排n个座位看成长度为n的序列
    当序列长度为n 时 则可以分为两种情况
    第n位做人
        所以n-2和n-1位都不能做人了 即有f[n-3]种
        当第n位做人 所以前面n-3是可以不做人的而f[n-3]所表示
        的是前n-3个座位至少做一人 故还需要加上一种情况时前n-3
        都不做人即f[n-3] +1
    第n位不做人
        所以与第n-1位的派法一样即f[n-1]种
        所以通项为f[n] = f[n-1] + f[n-3] + 1;
*/
#include<iostream>
using namespace std;
int main(){
    long long res[91];
    res[1] = 1;
    res[2] = 2;
    res[3] = 3;
    res[0] =0;
    for(int i =4;i<=50;i++){
        res[i] = res[i-1] + res[i-3] +1;
    }
    int n;
    while(cin>>n){
        cout<<res[n]<<endl;
    }
    return 0;
    }


2869加强斐波那契:

#include<stdio.h>
int main(){
long long a[31];
int i,n;
a[1]=1;a[2]=2;a[3]=3;
for(i=4;i<31;i++){
a[i]=a[i-1]+a[i-2]+a[i-3];
}
while(scanf("%d",&n)!=EOF){
printf("%lld\n",a[n]);
}
return 0;
}

解题小技巧:

①最好采用打表方式来存储数据 这样可以大大减少时间的浪费(前提是n的大小在100000 数据规模在1000000就最好不要采用打表了 此时即便打表成功也会出现错误的:内存超了 此时一般就是找规律 即f[n]一般是存在一个循环体的找到那个循环体 然后f[n]就可以求出来了)
②数据一般采用long long来存储因为采用递推越往后可能相邻n之间的数量级会相差10倍或者100倍 比如说斐波拉契数列当n= 100时 f[n] = 3.54224848179262*10^20 
③当long long类型存储不了 可以采用 Java BigInteger类型 这种类型是处理大数问题比较好的方法 方法简单 直接调用函数就可以了(缺点:耗内存比较大)或者 采用c++的大数模板(缺点是代码比较长 不容易理解)
④在想问题时 可以先把前几项写出来 然后结合题意分析问题 分析第n项时一般是建立在第n-1项 + 某一规律 比如母牛问题 就是第n 天牛的数量 = 第n -1 天的牛的数量 + 第n-2 天母牛的数量 
⑤平时多积累一些问题的通项公式并且记住几个特定的应用环境 比如说n个元素出栈的顺序有多少种、2*n个人有n个100元 n个50元怎么站才可以找开零钱问题、凸变形里怎么划线才使得三角形最多、n各节点组成的二叉排序树有多少种等等...这些都是卡特兰公式 h(n) = h(n-1) *(4*n-2)/n+1(对于卡特兰数最好用java来做 因为数据规模太大了);错排问题 h(n) = (n-1)(h(n-1) + h(n-2)) 例子 就是n 个元素排列每个元素都不在其相应的位置 选新郎问题;n条直线分割平面最多分割多少部分 h(n) = h(n-1) + 1+(1+n)n/2等等 这些通项公式多于几何数学问题和排列组合问题相关 可以多查阅相关资料
⑥递推最好不要用递归来写 因为这样会使程序运行的效率大打折扣的。


此篇大部分内容现实中同学总结。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值