递推算法(C++版)
- 格式:ppt
- 大小:349.00 KB
- 文档页数:3
算法总结之递推与递归递推算法递归算法⼤致包括两⽅⾯的内容:1)递归起点; 2)递归关系递推起点递归起点⼀般由题⽬或者实际情况确定,不由递归关系推出。
如果⽆法确定递归起点,那么递归算法就⽆法实现。
可见,递归起点是递归算法中的重要⼀笔。
递推关系递归关系是递归算法的核⼼。
常见的递归关系有以下⼏项:1)⼀阶递推;2)多阶递推;3)间接递推;4)逆向递推;5)多维递推。
下⾯通过栗⼦来详细介绍⼀下上述类别的递推关系。
1. ⼀阶递推在计算f(i)时,只⽤到前⾯项中的⼀项,如等差数列。
公差为3的等差数列,其递推关系为:f(i)=f(i-1)+3eg. 平⾯上10条直线最多能把平⾯分成⼏部分?分析:以直线数⽬为递推变量,假定i条直线把平⾯最多分成f(i)部分,则f(i-1)表⽰i-1条直线把平⾯分成的最多部分。
在i-1条直线的平⾯上增加直线i,易得i与平⾯上已经存在了的i-1条直线最多各有⼀个交点,即直线i最多被分成i段,⽽这i段将会依次将平⾯⼀分为⼆,即直线i将最多使平⾯多增加i部分。
所以,递推关系可表⽰为:f(i)=f(i-1)+i易得当0条直线时,平⾯为1部分。
所以f(0)=1为递推起点。
上述分析可⽤下⾯代码表⽰(c++):#define MAX 100int f[MAX] //存放f(i)int lines(int n){//输⼊n为直线数⽬//输出最多部分数int i;f(0)=1;for(i=1;i<=n;i++){f[i]=f[i-1]+3;}return f[i];}2. 多阶递推在计算f(i)时,要⽤到前⾯计算过的多项,如Fibonacci数列。
eg.求Fibonacci的第10项。
分析:总所周知,Fibonacci数列中的第n项等于第n-1项加上n-2项。
所以递推关系为f(i)=f(i-1)+f(i-2);且f[0]=f[1]=1。
C++代码如下:#define MAX 100int f[MAX];int fib(int n){//输⼊n为项数//输出第n个fib数int i;f[0]=0;f[1]=1;for(i=2;i<=n;i++){f[i]=f[i-1]+f[i-2];}return f[n]}3. 间接递推在计算f[i]时需要中间量,⽽计算中间量要⽤到之前计算过的项。
递推计算方法和应用数学中有不少算法属递推算法。
递推算法就是在一个循环体内随着循环控制变量的变化,逐一通过前面的k 个已知的或已算出的值计算当前待算的值的算法,所用的算式称为递推计算公式。
递推算法分为一维递推算法、二维递推算法和广义递推算法三类。
注意广义递推算法不用了解,一维递推算法又分单步算法和多步算法。
同类递推算法对应相同的基本程度模块,可以作为一个基本类型。
算式给出后程序就能给出,程序和算式有映射关系。
一维递推算法一维递推算法分为单步算法和多步算法。
所谓单步算法是指能用下面的公式表示的算法上式称为一维递推单步算式,00a x =为表头值。
它所对应的程序模块为x[0]:=a;for i=1 to n dox[i]:=f(x[i-1])多步法是指能用下面的公式表示的算法上式表示的算式称为一维递推多步算式,该算法称为一维多步(K 步)算法,1,1,0...-k x x x 的值称为表头值。
它所对应的程序模块为:for i:=0 to k-1 dox[i]:=a[i];for i:=k to n dox[i]:=f(x[i-k],x[i-k+1],…x[i -1]];这里要强调的是,为了使算式和程序之间有一对一的映射关系,应尽量使用数组元素,这也是称为一维递推算法的原因例1计算菲波拉契数列的前21项公式为程序为program p24;varf:array[0..21] of integer;i:integer;beginf[0]:=0;f[1]:=1;for i:=2 to 21 dof[i]:=f[i-1]+f[i-2];for i:=0 to 21 dowrite(f[i],' ');end.该程序和算法的特色为:1. 程序和数学公式有一对一的关系,编程难度低;2. 数组元素的序号本身具有时间顺序特征,程序中不出现数据传递;3. 程序由输入、计算和输出三部分组成,每个程序段都具有明确的单一功能,结构规范 程序中增加一个一维数组并不会发生内存溢出,但却能方便程序设计例2 小数十翻二。
迭代法迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应的是直接法(或者称为一次解法),即一次性解决问题。
迭代法又分为精确迭代和近似迭代。
“二分法”和“牛顿迭代法”属于近似迭代法。
迭代算法是用计算机解决问题的一种基本方法。
它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。
利用迭代算法解决问题,需要做好以下三个方面的工作:一、确定迭代变量。
在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。
二、建立迭代关系式。
所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。
迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。
三、对迭代过程进行控制。
在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。
不能让迭代过程无休止地重复执行下去。
迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。
对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。
例 1 :一个饲养场引进一只刚出生的新品种兔子,这种兔子从出生的下一个月开始,每月新生一只兔子,新生的兔子也如此繁殖。
如果所有的兔子都不死去,问到第12 个月时,该饲养场共有兔子多少只?分析:这是一个典型的递推问题。
我们不妨假设第 1 个月时兔子的只数为u 1 ,第 2 个月时兔子的只数为u 2 ,第 3 个月时兔子的只数为u 3 ,……根据题意,“这种兔子从出生的下一个月开始,每月新生一只兔子”,则有u 1 = 1 ,u 2 =u 1 +u 1 × 1 = 2 ,u 3 =u 2 +u 2 × 1 =4 ,……根据这个规律,可以归纳出下面的递推公式:u n =u n - 1 × 2 (n ≥ 2)对应u n 和u n - 1 ,定义两个迭代变量y 和x ,可将上面的递推公式转换成如下迭代关系:y=x*2x=y让计算机对这个迭代关系重复执行11 次,就可以算出第12 个月时的兔子数。
递推最小二乘法的一般步骤:1. 根据输入输出序列列出最小二乘法估计的观测矩阵ϕ:] )(u ... )1( )( ... )1([)(T b q n k k u n k y k y k ------=ϕ没有给出输出序列的还要先算出输出序列。
本例中, 2)]-u(k 1),-u(k 2),-1),-y(k -[-y(k )(T =k ϕ。
2. 给辨识参数θ和协方差阵P 赋初值。
一般取0θ=0或者极小的数,取σσ,20I P =特别大,本例中取σ=100。
3. 按照下式计算增益矩阵G :)()1()(1)()1()(k k P k k k P k G T ϕϕϕ-+-= 4. 按照下式计算要辨识的参数θ:)]1(ˆ)()()[()1(ˆ)(ˆ--+-=k k k y k G k k T θϕθθ5. 按照下式计算新的协方差阵P :)1()()()1()(---=k P k k G k P k P T ϕ6. 计算辨识参数的相对变化量,看是否满足停机准则。
如满足,则不再递推;如不满足,则从第三步开始进行下一次地推,直至满足要求为止。
停机准则:εϑϑϑ<--)(ˆ)1(ˆ)(ˆmax k k k i i i i 本例中由于递推次数只有三十次,故不需要停机准则。
7. 分离参数:将a 1….a na b 1….b nb 从辨识参数θ中分离出来。
8. 画出被辨识参数θ的各次递推估计值图形。
为了说明噪声对递推最小二乘法结果的影响,程序5-7-2在计算模拟观测值时不加噪声, 辨识结果为a1 =1.6417,a2 = 0.7148,b1 = 0.3900,b2 =0.3499,与真实值a1 =1.642, a2 = 0.715, b1 = 0.3900,b2 =0.35相差无几。
程序5-7-2-1在计算模拟观测值时加入了均值为0,方差为0.1的白噪声序列,由于噪声的影响,此时的结果为变值,但变化范围较小,现任取一组结果作为辨识结果。
递推算法集锦一、编写程序求50以内的勾股弦数。
即满足c*c=b*b+a*a的三个自然数,要求b>a。
将所有符合要求的a,b,c组合输出至屏幕。
解答:采用穷举算法,在主函数中实现。
#include<iostream>using namespace std;int main(){int a,b,c,count=0;cout<<"勾股弦数有:"<<endl;for(c=5;c<=50;c++) //产生50以内的数for(b=4;b<c;b++)for(a=3;a<b;a++){if(c*c==b*b+a*a){cout<<c<<','<<b<<','<<a<<"\t\t"<<c*c<<'='<<b*b+a*a<<endl;count++;if(count%10==0) cout<<endl;}}cout<<"共计:"<<count<<"个。
"<<endl;return 0;}二、设计函数factors(num,k),返回整数m中包含因子k的个数,如果没有该因子,则返回0。
(提示:必须先判断整数m能否被k整除。
)解法一:迭代法#include<iostream.h>int factors(int num,int k){ //缺省返回值为整型int count=0;while(num%k==0){count++;num/=k;}return count;}void main(){cout<<"factors(1875,5)="<<factors(1875,5)<<endl;cout<<"factors(64,3)="<<factors(64,3)<<endl;}解法二:递归函数,传值调用# include<iostream.h># include<iomanip.h>int factors(int m,int k,int num){if(m%k!=0){num=0; return num;}if(m%k==0)num=1;num+=factors(m/k,k,num);return num;}void main(){int m,k,num=0;cout<<"\n请输入一个整数和一个因子:";cin>>m>>k;cout<<'\n'<<m<<"的因子数目为:";cout<<factors(m,k,num)<<'\n';cout<<endl;}解法三:递归函数,使用引用参数#include<iostream.h>void factors(int m,int k,int &num){if(m%k!=0) return ;if(m%k==0)num++;factors(m/k,k,num);return ;}void main(){int m,k,num=0;cout<<"\n请输入一个整数和一个因子:";cin>>m>>k;cout<<'\n'<<m<<"的因子数目为:";factors(m,k,num);cout<<num<<endl;}三、歌德巴赫猜想指出:任何一个充分大的偶数都可以表示为两个素数之和。
递归与递推递推递归递归:从已知问题的结果出发,⽤迭代表达式逐步推算出问题的开始的条件,即顺推法的逆过程,称为递归。
递推:从已知道的若⼲项出发,利⽤递推关系依次推算出后⾯的未知项的⽅法,我们称为递推算法。
递推与递归不同:递归是从未知到已知逐步接近解决问题的过程,⽽递推从已知到未知。
递推算法是⼀种⽤若⼲步可重复运算来描述复杂问题的⽅法。
递推是序列计算中的⼀种常⽤算法。
通常是通过计算前⾯的⼀些项来得出序列中的指定项的值。
递推的关系式可以暴枚找规律,也可以化繁为简,例如铺砖问题,最后⼀列砖铺与不铺,以及最后两列砖铺与不铺的情况相加即可求出关系式。
⽽关于递归,就是函数中再次调取函数,从⽽使困难的问题化为“1+1”类型简单的问题,得出结果再还原,操作过程类似于“U”型。
递归的重点是找到递归关系和递归出⼝。
……(概念太多,直接摆题)经典例题统计奇数和偶数个3内存限制:128 MiB时间限制:1000 ms标准输⼊输出题⽬类型:传统评测⽅式:⽂本⽐较题⽬描述在所有的N位正整数中,有多少个数中有偶数个数字3?⼜有多少个数有奇数个3?由于结果可能很⼤,你只需要输出这个答案对12345取余的值。
输⼊格式输⼊⼀个数N(1<=N<=1000),输⼊形式为⽂件输⼊,以读到0或⽂件末尾结束。
输出格式对于每⼀个N位正整数,输出有多少偶数个3以及多少奇数个3,中间⽤空格隔开。
样例样例输⼊2样例输出73 17数据范围与提⽰分别找出奇数偶数的递推式样例说明:在所有的2位数字,包含0个3的数有72个,包含2个3的数有1个,共73个对于⼀位数,除3外,其他全为含有偶数个三(数组元素初始化),紧接着,对于两位数,13,23,30~39(除33外)【这⾥有9个数,也可以进⾏思考】,43,53,63,73,83,93含有奇数个三,再看三位数(差不多就可以找到规律……)。
声明:a数组存储含奇数个三的个数,b数组⽤于存储偶数i的数值 1 2 3 ……a[i] 1 17 674 ……b[i] 8 73 226 ……So,a[i]=(b[i-1]+a[i-1]*9)%12345,b[i]=(a[i-1]+b[i-1]*9)%12345;#include<cstdio>using namespace std;int main(){int n,a[10005],b[10005];a[1]=1,b[1]=8;for(int i=2;i<=1001;i++){a[i]=(b[i-1]+a[i-1]*9)%12345;b[i]=(a[i-1]+b[i-1]*9)%12345;}while(scanf("%d",&n)!=EOF){if(n==0)return 0;printf("%d %d\n",b[n],a[n]);}return 0;}Hanoi塔内存限制:128 MiB时间限制:1000 ms标准输⼊输出题⽬类型:传统评测⽅式:⽂本⽐较题⽬描述问题的提出:Hanoi塔由n个⼤⼩不同的圆盘和三根⽊柱a,b,c组成。
一、基本算法1.交换(两量交换借助第三者)例1、任意读入两个整数,将二者的值交换后输出.main(){int a,b,t;scanf("%d%d",&a,&b);printf(”%d,%d\n”,a,b);t=a; a=b; b=t;printf("%d,%d\n",a,b);}【解析】程序中加粗部分为算法的核心,如同交换两个杯子里的饮料,必须借助第三个空杯子。
假设输入的值分别为3、7,则第一行输出为3,7;第二行输出为7,3。
其中t为中间变量,起到“空杯子”的作用。
注意:三句赋值语句赋值号左右的各量之间的关系!【应用】例2、任意读入三个整数,然后按从小到大的顺序输出.main(){int a,b,c,t;scanf(”%d%d%d”,&a,&b,&c);/*以下两个if语句使得a中存放的数最小*/if(a>b){t=a; a=b; b=t;}if(a〉c){ t=a; a=c; c=t;}/*以下if语句使得b中存放的数次小*/if(b〉c) { t=b; b=c; c=t; }printf(”%d,%d,%d\n”,a,b,c);}2.累加累加算法的要领是形如“s=s+A”的累加式,此式必须出现在循环中才能被反复执行,从而实现累加功能。
“A”通常是有规律变化的表达式,s在进入循环前必须获得合适的初值,通常为0。
例1、求1+2+3+……+100的和。
main(){int i,s;s=0; i=1;while(i<=100){s=s+i; /*累加式*/i=i+1; /*特殊的累加式*/}printf(”1+2+3+...+100=%d\n”,s);}【解析】程序中加粗部分为累加式的典型形式,赋值号左右都出现的变量称为累加器,其中“i = i + 1”为特殊的累加式,每次累加的值为1,这样的累加器又称为计数器。
3.累乘累乘算法的要领是形如“s=s*A"的累乘式,此式必须出现在循环中才能被反复执行,从而实现累乘功能。