司延 OI 第三章 第三节 递推和递归

递推就是用别人来算自己,递归就是用自己更新别人。如果把这两部分单独拿出来写一个函数,递归有一个特征就是 我 调 用 我 自 己
以下例题全部来自洛谷

1.P2562 [AHOI2002]Kitty猫基因编码
本题涉及string相关函数。
代码为递归写法

#include
#include
#include
#include
#include
using namespace std;
/*
使用到的string函数 
a.find(char x或string x):返回a里面第一个是x的字符/字符串的首字母下标,如果没有就返回-1
a.substr(int b,int c):返回从b开始,长度为c的字符串
*/
string gene;
string t(string gene,int n){//递归函数。gene是基因,n是基因长度 
 if(gene.find('1')==-1)//寻找1 
  return "A";
 if(gene.find('0')==-1)//寻找0 
  return "B";
 //否则既有1又有0 
 return "C"+t(gene.substr(0,n/2),n/2)+t(gene.substr(n/2,n/2),n/2);
}
int main(){
 cin>>gene;
 cout<<t(gene,gene.size());
 return 0;
}

2.P2626 斐波那契数列(升级版)
NOIP 1997 PJ

/*斐波那契数列0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765...
第0项是0,第1项是第一个1。
从第3项开始,每一项都等于前两项之和。 
f(1)=1
f(2)=1
f(n) = f(n-1) + f(n-2)
*/

//递推版本 
#include
#include
#include
#include
#include
using namespace std;
int num,n,f[55]={0,1,1};
int main(){
 cin>>n;
 for(int i=3;i<=n;i++)//i=1 会改变数列 
  f[i]=(f[i-1]+f[i-2])%(1<<31);
 cout<<f[n]<<'=';
 for(int i=2;i<=f[n];i++)//分解因数 
  while(f[n]%i==0){
   num++;
   if(num==1)
    cout<<i;
   else cout<<'*'<<i; 
  f[n]/=i;
  }
return 0;
}

//递归版本 
#include
#include
#include
using namespace std;
int num,n,f[55]={0,1,1};
inline int dg(int n){
 if(n==0)//f[0]=0,不可用下一行的if进行记忆 
  return 0;
 if(f[n])
  return f[n];
 f[n]=(dg(n-1)+dg(n-2))%(1<<31);
 return f[n];
} 
int main(){
 cin>>n;
 cout<<dg(n)<<'=';
 for(int i=2;i<=f[n];i++)
  while(f[n]%i==0){
   num++;
   if(num==1)
    cout<<i;
   else cout<<'*'<<i; 
  f[n]/=i;
  }
return 0;
}

3.P1028 数的计算
NOIP 2001 PJ

/*
f[0]=1 //0
f[1]=1 //1
f[2]=2=1+1 //2,12
f[3]=2=1+1 //3,13
f[4]=4=2+1+1 //4,14,24,124
f[5]=4=2+1+1 //5,15,25,125
f[6]=6=2+2+1+1 //6,16,26,36,126,136
f[7]=6=2+2+1+1 //7,17,27,37,127,137
f[i]=f[1]+f[2]+...+f[i/2]  递推公式 
*/ 
//递推版本 
int f[1005],n;
int main(){
 n=read();
 f[0]=1,f[1]=1;
 for(int i=2;i<=n;i++){//递推过程 
  for(int j=1;j<=i/2;j++)
   f[i]+=f[j];
 f[i]+=f[0];
 }
 write(f[n]);
 cout<<endl;
 return 0;
}
//递归版本 
#define maxn 1005
int f[maxn],n;
inline int dg(int n){
 if(n==1||n==0)
  return 1;
 if(f[n])//记忆剪枝部分,之前已经算出来了的就直接调用,而不是再算一遍增加复杂度 
  return f[n];
 int ans=0;
  for(int j=1;j<=n/2;j++)
   ans+=dg(j);
 return  f[n]=ans+1;
}
int main(){
 cin>>n;
 dg(n);
 cout<<dg(n);//若输出f[n]应提前初始化f[0]和f[1] 
 return 0;
}

4.P1096 Hanoi 双塔问题
NOIP2007 PJ

/*当初我在4399上玩汉诺塔小游戏玩到怀疑人生。 
我们把从上到下的圆盘两两编号为1,2,3,...n。 
hanoi[1]=2:A柱子上只有2个盘子时只需要2步,即分别A→C即可。
注意题目条件:输入的是n,但圆盘数为2n。不过这并没什么大的干扰,因为最后我们
会发现,为了实现最少步骤,两个尺寸相同的圆盘位置变化必须是同步的。 
n=2即2x2个圆盘时,最简单路径为:1放到B柱暂存,2放到C柱,再把1放过去,共6步。
n=3即2x3个圆盘时,最简单路径为;1(A→C),2(A→B),1(C→B),3(A→C), 1(B→A),2(
 B→C),1(B→C),2x7=14步。 
因为后续的推导比较麻烦而司延时间有限就不在此推导了,大家懒得找游戏也可以用
不同大小的夹子之类的小物件模拟一下,对于相对抽象的代码实现来说模拟还是很重
要的。 
多次模拟后我们可以得到的递推公式为:hanoi[n]=2*hanoi[n-1]+2
*/ 
#include
#include
#include
#include
#include
#include
#include
#define maxn 505
using namespace std;
int hanoi[maxn],b[maxn];;
int n,len=1;
int main(){
 hanoi[1]=2;//初始化,A上只有1个圆盘时需要2步 
    cin>>n;//输入数字 
    n--;//递归前我们记录了n=1的情况,所以往下计算时从n=2开始计算结果即可,所以n-1 
    while(n--){//使用高精度递归 
        int x=0;//从个位数开始记录高精度中每一位数字的下一位对它的进位 
        for(int i=1;i<=len;i++){//开始按位存储 
            hanoi[i]=hanoi[i]*2+x;//高精度乘法 
            if(i==1)
                hanoi[i]+=2;
            x=hanoi[i]/10;//记录进位 
            //加减乘除都是从个位开始往高位算,高精也是,算一位往前走一位 
            hanoi[i]%=10;//求第i位和它之前位上的数字 
        }
        hanoi[len]+=x; 
        if(hanoi[len])//如果这一位还有数,len+1保证下次计算结果仍然正确 
            len++;
    }
    //因为算到最高位后len仍然是要+1的,之后len位为0,输出时应去掉 
    for(int i=len-1;i>=1;i--)//存储时低位在前,所以要倒着输出数组 
        cout<<hanoi[i];
    return 0;
}
//另外这道题最后几组数据都是需要高精实现的,否则不是满分。

你可能感兴趣的:(基础算法)