对于递归的理解:
1、要有跳出递归的条件
2、不断地调用本身
注意:当满足跳出递归条件的时候,会返回上一层
狭义一点就是:递归有点像高中学过的数列,等比、等差数列的这种
分析思路:首先找到第一、二项,作为跳出条件
然后固定最后一、二项,分析前面的出现的情况
对于使用递归超时问题:
原因:计算重复次数太多
解决办法:在递归函数中用一个数组来记录之前计算好的值
参考文章:递归算法中的超时问题解决方法
例题一:
杭电oj——一只小蜜蜂(http://acm.hdu.edu.cn/showproblem.php?pid=2044#top)
正确代码:
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
long long a[55];
int main()
{
int t,m,n;
a[0]=0;
a[1]=1;
a[2]=2;
for(int i=3;i<=50;i++){
a[i]=a[i-1]+a[i-2];
}
cin>>t;
while(t--){
cin>>m>>n;
cout<<a[n-m]<<endl;
}
return 0;
}
错误代码:
(直接使用递归,在递归函数中用数组来记录数据,就不会超时了。问题是,案例能过,但是最后还wrong answer)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int f(int t);
long long memo[1000];
int main()
{
int cnt;
cin>>cnt;
int m,n;
while(cnt--){
cin>>m>>n;
cout << f(n-m) << endl;
}
return 0;
}
int f(int t){
if(t==0) {
return 0;
}
else if(t==1){
return 1;
}
else if(t==2){
return 2;
}
else if(memo[t]){
return memo[t];
}
else{
return memo[t]=f(t-1)+f(t-2);
}
}
例题二:
杭电oj——不容易系列之(3)—— LELE的RPG难题
分析:
正确代码:
#include<iostream>
using namespace std;
int main()
{
int n;
long long a[55];
a[0]=0;//当只有0、1、2、3个方格的时候
a[1]=3;
a[2]=6;
a[3]=6;
for(int i=4;i<=50;i++) {
a[i]=a[i-1]+a[i-2]*2;
}
while(cin>>n){
cout<<a[n]<<endl;
}
return 0;
}
例题三:
杭电oj——骨牌铺方格
代码:
#include<iostream>
using namespace std;
int main()
{
long long a[55];
a[1]=1;
a[2]=2;
for(int i=3;i<=50;i++){
a[i]=a[i-1]+a[i-2];
}
int n;
while(cin>>n){
cout<<a[n]<<endl;
}
return 0;
}
例题四:
杭电oj——阿牛的EOF牛肉串
代码:
#include<iostream>
using namespace std;
int main()
{
long long a[55];
a[1]=3;
a[2]=8;
for(int i=3;i<=50;i++){
a[i]=2*a[i-1]+2*a[i-2];
}
int n;
while(cin>>n){
cout<<a[n]<<endl;
}
return 0;
}
例题五:
错排问题:
杭电oj——神、上帝以及老天爷
参考:https://blog.csdn.net/pengkexiaohuai/article/details/47256937
代码:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
double a[21];
a[1]=0;
a[2]=1;
for(int i=3;i<=20;i++){
a[i]=(i-1)*(a[i-1]+a[i-2]);
}
int n;
int t;
double sum; //注意这里的数据类型,因为下面要与double型相除
cin>>n;
while(n--){
cin>>t;
sum=1;
for(int i=1;i<=t;i++){
sum*=i;
}
printf("%.2lf%%\n",a[t]/sum*100);
}
return 0;
}
例题六:
杭电oj——不容易系列之(4)——考新郎
思路就是:
首先抽出一部分新郎(用组合数抽出新郎)
然后将这部分新郎进行排错
参考:https://blog.csdn.net/qq_33171970/article/details/50649730
https://blog.csdn.net/qq_40507857/article/details/82821492
错误代码:(组合数计算错误,不晓得怎么改,换个写法就可以了)
#include<iostream>
#include<cstdio>
using namespace std;
long long a[25][25];
long long b[25];
int main()
{
a[20][20]={0};
a[0][0]=1;
a[0][-1]=0;
for(int i=1;i<=20;i++){
for(int j=0;j<=i;j++){
a[i][j]=a[i-1][j-1]+a[i-1][j]; //计算组合数会有问题,就是只要遇到1
//就会重复输出两遍
printf("%lld\n",a[i][j]);
}
}
b[1]=0;
b[2]=1;
for(int i=3;i<=20;i++){
b[i]=(i-1)*(b[i-1]+b[i-2]);
}
int n;
cin>>n;
int e,f;
while(n--){
cin>>e>>f;
//printf("%lld\n",a[e][f]);
//printf("%lld\n",b[f]);
printf("%lld\n",a[e][f]*b[f]);
}
return 0;
}
正确代码:
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<math.h>
using namespace std;
long long ans[25];
int a,b,t;
long long c(int m,int n){
if(n==0) return 1; //需要注意加上c(n,0)=1
if(m==n) return 1;
if(n==1) return m;
else return c(m-1,n-1)+c(m-1,n);
}
int main(){
ans[1]=0;ans[2]=1; //计算f(n),结果用ans数组保存
for(int i=3;i<=20;i++){
ans[i]=(ans[i-1]+ans[i-2])*(i-1);
}
ans[1]=1; //重新赋值以免后面计算出现异常
cin>>t;
while(t--){
cin>>a>>b;
cout<<c(a,a-b)*ans[b]<<endl;
}
return 0;
}
例题七:
杭电oj——折线分割平面
参考:https://www.cnblogs.com/zy691357966/p/5480433.html
分析思路:计算上一个数据+线段数+射线数-1(减一是因为两根折线内部只能够形成一个平面)
正确代码:
#include<iostream>
using namespace std;
int main()
{
long long a[10001];
a[1]=2;
for(int i=2;i<=10000;i++){
a[i]=a[i-1]+4*(i-1)+2-1;
}
int n;
cin>>n;
int m;
while(n--){
cin>>m;
cout<<a[m]<<endl;
}
return 0;
}