递归与递推总结

汉诺塔问题思路:移动过程只有三步1.A移动N-1个盘到B: F(n-1);2.A移动最大盘到C: F(1)即为1;3.B移动N-1个盘到C: F(n-1);#include <iostream>#include <cstdio>using namespace std;void slove(int n,char a,char b,char c)///有n个塔...
摘要由CSDN通过智能技术生成
汉诺塔问题

思路
移动过程只有三步
1.A移动N-1个盘到B: F(n-1);
2.A移动最大盘到C: F(1)即为1;
3.B移动N-1个盘到C: F(n-1);
移动次数的公式F(n)=F(n-1)*2+1

#include <iostream>
#include <cstdio>
using namespace std;
void slove(int n,char a,char b,char c)///有n个塔层由a经过b的中转运送到c
{
   
    if(n==1)///只有一个的时候,直接将a上的放到c上
    {
   
        printf("%c-%d-%c\n",a,1,c);
        return;
    }
    else///将n-1层塔由a到b,当最后一个(第n个)运到c时,再由b运到c
    {
   
        slove(n-1,a,c,b);///有n-1个塔层由a经过c的中转运送到b
        printf("%c-%d-%c\n",a,n,c);///把a中的1层塔移动到c
        slove(n-1,b,a,c);///有n-1个塔层由b经过a的中转运送到c
    }
}
int main()
{
   
    int n;
    cin>>n;
    slove(n,'A','B','C');
    return 0;
}


问题 P: 【递归与递推】Hanoi双塔问题

题目
给定A,B,C三根足够长的细柱,在A柱上放有2n个中间有空的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。现要将 这些国盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2) A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为2n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。
输入
输入一个正整数n,表示在A柱上放有2n个圆盘。
输出
输出一个正整数,为完成上述任务所需的最少移动次数An。
思路
F(n)=F(n-1)*2+2

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string ans[205];
string add(string a,string b)///高精度加法
{
   
    string c;
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    int carry=0,temp;
    for(int i=0;i<a.size()||i<b.size();i++)
    {
   
        temp=carry;
        if(i<a.size()) temp+=a[i]-'0';
        if(i<b.size()) temp+=b[i]-'0';
        c.push_back(char(temp%10+'0'));
        carry=temp/10;
    }
    if(carry!=0) c.push_back(char('0'+carry));
    reverse(c.begin(),c.end());
    int i;
    for(i=0;c[i]=='0'&&i<c.size()-1;i++);///消除前导0,但保证至少有一个
    c=c.substr(i,c.size()-i);
    return c;
}
string multiply(string a,string b)
{
   
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    int c[10005]={
   0};
    string ans;
    for(int i=0;i<a.size();i++)///注意下标都是从0开始
    {
   
        for(int j=0;j<b.size();j++)
        {
   ///i+j为两个数相乘完的那个数所在位置,例如一个数的第二位×另一个数的第二位,所得数在结果的第四位
            c[i+j]=c[i+j]+(a[i]-'0')*(b[j]-'0');///算法核心,不进位乘法
        }
    }
    int temp,carry=0;///该位数的和temp,进位carry,与加法类似
    for(int i=0;i<a.size()+b.size();i++)
    {
   
        temp=c[i]+carry;
        c[i]=temp%10;
        carry=temp/10;
    }
    for(int i=0;i<a.size()+b.size();i++) ans.push_back(char('0'+c[i]));
    int i;
    for(i=ans.size()-1;ans[i]=='0'&&i>=1;i--); ans=ans.substr(0,i+1);
    if(carry!=0) ans.push_back(char('0'+carry));
    reverse(ans.begin(),ans.end());
    return ans;
}
void getans()
{
   
    ans[1]="2";
    string two("2");
    for(int i=2;i<=200;i++)
    {
   
        ans[i]=add(multiply(ans[i-1],two),two);
    }
}
int main()
{
   
    getans();
    int n;cin>>n;
    cout<<ans[n]<<endl;
    return 0;
}


问题 D: 【递归与递推】2的幂次方

题目
任何一个正整数都可以用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≤20000)
输出
符合约定的n的0,2表示(在表示中不能有空格)
思路
参考算法:递归输出某十进制数的二进制表示的算法。(主要是在递归回溯的时候才输出,而非计算出来就输出。)

#include <stdio.h>
void fun(int n)
{
   
    int t;
    if(n==0)
        return;
    else
    {
   
        t=n%2;
        fun(n/2);
        printf("%d",t);
    }
}
int main()
{
   
    fun(5);
    return 0;
}

本着从易到难的原则,可以考虑先实现将137表示为:2(7)+2(3)+2(0)的程序。
关于加号的输出:可以考虑判断当前项是否二进制序列的最高位(x递归到下一层slove(x/2,bit+1)的数x/2是0,即返回了)。是最高位则当前项左侧不输出“+”,否则在当前项左侧输出“+”.
关于把指数也转变为0和2的序列:在输出每一项时判断指数是否超过1,超过则先输出“2(”,然后把该指数与0传入递归函数,递归显示该指数的表示。然后在输出后半边括号。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void slove(int x,int bit)
{
   
    if(x==0) return ;
    else
    {
   
        slove(x>>1,bit+1);
        if(x%2)///回溯的时候才输出
        {
   
            if(bit==1)
            {
   
                if(x!=1) cout<<"+2";
                else  cout<<2
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值