递归练习

1.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?

1.题目分析

每一个村子卖出之前的数量都是卖出之后的数量+1再*2,从经过了七个村子后还剩两只鸭子倒推即可。

2.算法构造

        每经过一个村子卖去所赶鸭子的一半又一只,那么倒推时反过来先+1再*2。

3.算法实现

/*

Author:蔡从彪

Date:2018.11.15

Version:0.1

Description:常规算法求解鸭子总数和每次卖出的数量

*/

#include<iostream>

using namespace std;

void main()

{

         int sellnum; //每次卖出数量

         int eveleave; //每次剩余数量 

         eveleave=2; //第七次卖出剩余数量

 

         for(int i=0;i<7;i++)

         {

                  sellnum=(eveleave+1)*2-eveleave; //第7-i个村卖出的数量

                  eveleave=(eveleave+1)*2; //第7-i个村剩余数量

                  cout<<"第"<<7-i<<"次卖出的数量"<<sellnum<<endl;

         }

         cout<<"总数"<<eveleave<<endl;

 

}4.运行结果

 

2.角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。

如:输入22,

输出 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

 STEP=16

1.题目分析

按照题目的要求顺着题意就行

2.算法构造

        输入数字,在循环里判断是奇数还是偶数,然后执行相应的操作,同时记录执行次数,当算出来的数字为1时跳出循环结束程序。

3.算法实现

/*

Author:蔡从彪

Date:2018.11.15

Version:0.1

Description:常规算法验证角谷定理

*/

 

#include<iostream>

using namespace std;

void main()

{

         int num; //输入的数

         int temp=1; //循环控制变量

         int STEP=0; //循环次数

        

         cout<<"请输入数字:"<<endl;

         cin>>num;

         while(temp)

         {

                  STEP+=1;

                  if(num%2==0)

                          num=num/2;

                  else

                          num=num*3+1;

                  if(num==1)

                          temp=0;

                  else

                          continue;

         }

         cout<<STEP<<endl;

}

4.运行结果

 

3.电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。

1.题目分析

除了0,1之外,其他数字上最少都有3个字符,其中7和9上有4个字符,可以假设0,1都是空字符,若电话号码只有一位数,比如说4,那么其代表的单词为g,h,i, 接着若电话号码升级到两位数,比如42,在选择一个第一位数字所代表的字符的基础上,遍历第二位数字所代表的字符,直到遍历完第一位数字代表的所有字符。就拿42来说,4所能代表的字符为ghi,2所能代表的字符为abc,首先让4代表g,接着遍历2所能代表的所有字符,即可得到ga,gb,gc,然后再让4代表h,再次遍历2所能代表的所有字符,即可得到ha,hb,hc,最后让4代表i,那么同理可得到ia,ib,ic,以此类推。

 

2.算法构造

递归出口是,当输入的是一个数字时,返回这个数字所有可能性的组合,递归体是当输入一串数字,每个数字代表不同的字符串,返回最后一个数字跟前面已产生的字符串进行组合。首先建一个数组,用来存放每个数字代表的字符串组合,然后在建一个数组,用来存放每个字符串的长度,在函数中,先进行判断是否是最后一位,然后根据判断执行函数。

 

3.算法实现

/*

Author:蔡从彪

Date:2018.11.15

Version:0.1

Description:使用递归求解电话号码代表的字母可能的组合和组合数

*/

 

#include <iostream>

using namespace std;

char tel[10][10]={" "," ","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};//0-9数字代表的字母

int num[10]={0,0,3,3,3,3,3,4,3,4};//0-9数字代表的字母数

int input[11];//存储输入的号码

int telindex[11];//数字目前所代表的字符在其所能代表的字符集中的位置

 

void fun(int *input,int *telindex,int index,int n)

{

         //判断是否递归到数组最后一位

         if (index==n)

         {

                  for (int i=0;i<n;i++)

                  {

                          cout<<tel[input[i]][telindex[i]];

                  }

                  cout<<" ";

         }

         else

         {

                  if (input[index]==1||input[index]==0)//排除1和0造成的递归中断的干扰

                  {

                          index++;

                  }

                  for (telindex[index]=0;telindex[index]<num[input[index]];telindex[index]++)

                  {

                          fun(input,telindex,index+1,n);        

                  }

         }

}

void main()

{

         int n;//存储号码位数

//     int m=0;//记录除1和0之外号码的长度

         int sum=1;//存储组合数

         cout<<"请输入号码位数:"<<endl;

         cin>>n;

         cout<<"请输入电话号码:"<<endl;

         for (int i=0;i<n;i++)

         {

                  cin>>input[i];

                  if (input[i]==0||input[i]==1)//排除1和0之后在计算组合数

                  {

                          continue;

                  }

                  else

                  {

                          sum*=num[input[i]];//计算组合数

                  }

         }      

         cout<<"组合数:"<<sum<<endl;

         fun(input,telindex,0,n);//调用递归

         cout<<endl;//递归结束换行

        

}

 

4.运行结果

5.经验归纳

做递归算法时一定要保持头脑清醒!!

 

4.日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?

1.题目分析

从数学的思维来分析,倒推就可以了:

总共2520,分到最后每人是2520/6=420

老六拿到后连同原先的桔子分1/3给老大,所以老六没分给老大之前是420*3/2=630,分给老大的是630/3=210; 老大最后也是420,所以老大在分给老二后的橘子数为420-210=210; 而老大将分给你的桔子的1/8给老二,故老大未分给老二前的橘子数为210*8/7=240;老二拿到后连同原先的桔子分1/7给老三,设老二本身的橘子数为x,则(x+30)*6/7=420;老二本身的橘子数为460….

以此类推!

 

2.算法实现

/*

Author:蔡从彪

Date:2018.11.15

Version:0.1

Description:常规算法分橘子问题

*/

 

#include <iostream>

using namespace std;

void main()

{

    int a[6] = {0};//原来的橘子数

    int next = 0;//暂存传递的橘子数

    int ave = 2520/6;

        

    for (int i = 0; i < 6; i++)

    {

        if (0 == i)    /*求老大桔子数时,利用老六与老大桔子数量的关系求解*/

        {

                          a[i] = (ave - 210)*(8 - i)/(7 - i) - next;

                          next = a[i] + next - (ave - 210);

        }

        else

        {

                          a[i] = ave*(8 - i) / (7 - i) - next;

                          next = a[i] + next -ave;

        }

                 

        cout<<"第"<<i+1<<"个兄弟原来的橘子数为:"<<a[i]<<endl;

    }

}

 

3.运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值