递归与递推

递推 递归

递归:从已知问题的结果出发,用迭代表达式逐步推算出问题的开始的条件,即顺推法的逆过程,称为递归。
递推:从已知道的若干项出发,利用递推关系依次推算出后面的未知项的方法,我们称为递推算法。
递推与递归不同:递归是从未知到已知 逐步接近解决问题的过程,而递推从已知到未知。
递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算前面的一些项来得出序列中的指定项的值。
递推的关系式可以暴枚找规律,也可以化繁为简,例如铺砖问题,最后一列砖铺与不铺,以及最后两列砖铺与不铺的情况相加即可求出关系式。
而关于递归,就是函数中再次调取函数,从而使困难的问题化为“1+1”类型简单的问题,得出结果再还原,操作过程类似于“U”型。递归的重点是找到递归关系和递归出口。
……(概念太多,直接摆题)

经典例题

统计奇数和偶数个3

内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
在所有的N位正整数中,有多少个数中有偶数个数字3?又有多少个数有奇数个3?由于结果可能很大,你只需要输出这个答案对12345取余的值。
输入格式
输入一个数N(1<=N<=1000),输入形式为文件输入,以读到0或文件末尾结束。
输出格式
对于每一个N位正整数,输出有多少偶数个3以及多少奇数个3,中间用空格隔开。
样例
样例输入
2
0
样例输出
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组成。开始时,这n个圆盘由大到小依次套在a柱上,如图所示。
要求把a柱上n个圆盘按下述规则移到c柱上:
规则:
(1)、一次只能移一个圆盘;
(2)、圆盘只能在三个柱上存放;
(3)、在移动过程中,不允许大盘压小盘。
问将这n个盘子从a柱移动到c柱上,总计需要移动多少个盘次?
输入格式
一个数n(1≤n≤63)
输出格式
一个数,总计需要移动多少个盘次
样例
样例输入
3
样例输出
7

一道十分经典的游戏,其实也可以直接找规律……,在数学上方法数是2^n-1,这是递推。也可用递归来解决,其实,整体思想即是将最后一个头上的n-1个盘子移开,把其放在C的最上面
(即是上一次操作圆盘的头顶),再对下一个圆盘进行该操作,直至n个圆盘全部归位,递归方法暂时不呈现……最后,开long long,int一般会炸,除非题目要求边求边模。
#include<cstdio>
using namespace std;
int main(){
	long long int n,sum=1;
	scanf("%lld",&n);
	for(long long int i=1;i<=n;i++){
		sum*=2;
	}
	printf("%lld",sum-1);
	return 0;
} 

凸n边形的不同划分方式

内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
卡特兰数又称卡塔兰数,英文名Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名。
最初,给卡塔兰数建立的数学模型是:一个凸n边形,通过不相交于n边形内部的对角线,把n边形拆分成若干三角形,不同的拆分数目用hn表示,hn即为Catalan数。例如五边形有如下五种拆分方案(如图),故h5=5。求对于一个任意的凸n边形相应的hn。
输入格式
一个正整数n,代表凸n边形的边数 (2≤n≤37)
输出格式
一个正整数,凸n边形划分成若干三角形的不同划分方式
样例
样例1输入
4
样例1输出
2
样例2输入
5
样例2输出
5

画图!!!
设h(n)为catalan数的第n项,令h(0)=1,h(1)=1,catalan数满足递推式[3]:
h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)(n≥2)
例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2
h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5
另类递推式:
h(n)=h(n-1)*(4*n-2)/(n+1)
h(n+1)=h(n)*(4*n+2)/(n+2)
递推关系的解为:
h(n)=C(2n,n)/(n+1)(n=0,1,2,...)
递推关系的另类解为:
h(n)=C(2n,n)-C(2n,n-1)(n=0,1,2,...)
用循环嵌套模拟求和符号
#include<cstdio>
using namespace std;
int main(){
	int n;
	long long a[10005];
	scanf("%d",&n);
	a[1]=1,a[2]=1;
	for(int i=3;i<=n;i++){
		for(int j=2;j<=i-1;j++){
			a[i]+=a[j]*a[i-j+1];
		}
	}
	a[2]=0;
	printf("%lld",a[n]);
	return 0;
} 
最后将a[2]赋值为0是关键,因为很有可能会有这组数据(哪有两边形???)

斐波那契数列

内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
斐波那契数列0,1,1,2,3,5,8,13,21,34,55,...,从第三项起,每一项都是紧挨着的前两项的和。写出计算斐波那契数列的任意一个数据项递归程序。
输入格式
所求的项数。
输出格式
数据项的值。
样例
样例输入
10
样例输出
34

好吧,没啥可说,规则也有,家喻户晓,直接上代码。递推没难度,主要考察对递归的运用。
法一 递推
#include<cstdio>
int a[50];
int main(){
	int n;
	scanf("%d",&n);
	a[1]=1;
	a[2]=1;
	for(int i=3;i<=46;i++){
		a[i]=a[i-1]+a[i-2];
	}
	printf("%d",a[n]);
	return 0;
}
法二 递归
#include<cstdio>
int fbnq(int n){
	if(n<=1)return n;
	return fbnq(n-1)+fbnq(n-2);
}
int main(){
	int a;
	scanf("%d",&a);
	printf("%d",fbnq(a-1));
	return 0;
} 

2的幂次方表示

内存限制:128 MiB
时间限制:1000 ms
标准输入输出
题目类型:传统
评测方式:文本比较
题目描述
任何一个正整数都可以用2的幂次方表示。例如:
137=27+23+20
同时约定方次用括号来表示,即ab可表示为a(b)。由此可知,137可表示为:
2(7)+2(3)+2(0)
进一步:7=22+2+20(21用2表示)
3=2+20
所以最后137可表示为:
2(2(2)+2+2(0))+2(2+2(0))+2(0)
又如:1315=210+28+25+2+1
所以1315最后可表示为:
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)
输入格式
一个正整数n(n≤20000)。
输出格式
一行,符合约定的n的0,2表示(在表示中不能有空格)。
样例
样例输入
137
样例输出
2(2(2)+2+2(0))+2(2+2(0))+2(0)

逐步递归分解拆分直至待拆分数为0或1,几个小细节需要处理
1.x==0时,输出2(0),而不是2;
2.x==1时,直接输出2;
3.else 先输入前括号,拆完后再输出后括号
4.如果当前n不为0,可已经无法拆分,输出加号
#include<bits/stdc++.h>
using namespace std;
inline void f(int n){
	if(n==0)return;
	int sum=1,x=0;
	while(sum*2<=n){
		sum*=2,x++;
	}
	if(x==0)cout<<"2(0)";
	else if(x==1)cout<<"2";
	else{
		cout<<"2(";
		f(x);
		cout<<")";
	}
	n-=sum;
	if(n!=0){
		cout<<"+";	
		f(n);
	}
} 
int main(){
	int n;
	cin>>n;
	f(n);
	return 0;
}
posted @ 2021-04-01 13:14  黄逸飞重庆八中  阅读(1077)  评论(0编辑  收藏  举报