递归思想以及实例练习

思想分析:

     1.对问题的细化成小问题。

     2.自己调用比自己小一个规模的自己。

     3.有结束条件。

满足条件:

     1.有递归公式。问题能够分解为一个一个于自身类似的小问题。

     2.有确切的边界。能够最后分解为一个有确定解的问题。

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

分析:经过7个村庄后还剩两只鸡鸭子,每经过一个村庄卖当前鸭子的一半加一只,所以递归体是经过前一个村子的鸭子数除以2再减去1就是到达下一个村子的时候的鸭子数,所以要想求在第一个村子的鸭子数,必须从后往前推。

算法: 当i=0时,结束递归调用,当i>0时,故有:

            If(i=0)

                 Cout<< “共有x只鸭子”;

            Else

                  Returnf(x+1);

代码实现:

#include <stdio.h>
#include "iostream"
using namespace std;
 
int number = 2,x,i=7;
 
int Number(int i) 
{
     	if(0 == i)           //当i为0时,结束递归调用 
	    {
		    cout << "他出发时共赶了" << number << "只鸭子。" << endl;  //当经过的村子数为0时,number为出发时的鸭子数 
	    }
	     else
     	{ 
	     	number = (number + 1 ) * 2;   //计算在经过第i个村子前的鸭子数number
           	x = number / 2 + 1;           //计算在经过第i 个村子时卖的鸭子数x 
	     	cout << "经过第" << i << "个村子时,他卖出" << x << "只鸭子。" << endl;
		    return Number(i - 1);
	    } 
}
int main()
{
	Number(7);	
}

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

如:输入22,

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

 STEP=16

分析:设fun(n)表示关于自然数n的一个函数,由题意已知,当n=1时,fun(1)=1。

           当n>1且n为偶数时,fun(n)=fun(n/2);

           当 n>1且n为奇数时,fun(n)=fun(3*n+1)。

          最后得到自然数1的运算次数为每次运算次数之和。

算法:fun(n)=1          n=1

           fun(n)=fun(n/2)    n>1且n为偶数

           fun(n)=fun(3*n+1)  n>1且n为奇数

代码实现:

#include<iostream>
using namespace std;

int Angle(int n,int i)
{
	if(n==1)  //当n 为1时,退出递归
	{
		cout<<endl<<"STEP="<<i<<endl; //输出次数
		return 1;
	}
	else
	{
		if(n%2==0) //当n为偶数时
		{
			cout<<n/2<<" ";
			i=i+1;  //次数加1
			return Angle(n/2,i);
		}
		else  //当n为奇数时
		{
			cout<<3*n+1<<" ";
			i=i+1;
			return Angle(3*n+1,i);
		}
		cout<<endl<<"STEP="<<i<<endl; //输出次数
	}
}

void main()
{
	int m,j=1;//m为自然数,j为运行次数
	scanf("%d",&m);
	Angle(m,j);
	system("pause");
	return;
}

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

分析:0到9所代表的字符0:"" 1:"" 2:ABC 3:DEF 4:GHI 5:JKL 6:MNO 7:PQRS 8:TUV 9:WXYZ

算法:例如:23  

              1.show(0,2)-> output[0]=A-> show(1,2)-> 1!=2-> output[1]=D->

              2.k=1 show(2,2)-> 2=len-> 输出AD-> i+1-> output[1]=E-> show(2,2)-> 2=len-> 输出AE i=2-> output[1]=F->                             show(2,2)-> 2=len-> 输出AF

             3.再回到k=0-> i=1 output[0]=ch[0][1]=B  输出BD,BE,BF i=2 输出CD,CE,CF

代码实现:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std; 

const char ch[10][10]={ //用数组存放0到9所表示的字符
	"",//0
	"",//1
	"ABC",//2 
	"DEF",//3
	"GHI",//4
	"JKL",//5
	"MNO",//6
	"PQRS",//7
	"TUV",//8
	"WXYZ"//9 
	};
const int total[10]={0,0,3,3,3,3,3,4,3,4}; //各个数字代表的字符总数构成的数组 
char input[20];	//保存输入电话字符数组 
char output[20];	//输出可能字符组合 

void show(int k,int len){  	
	if(k==len){ 
		output[len]='\0';  //设为结束标志,输出 
	    printf("%s\n",output);
		return ;
	}
	for(int i=0;i<total[input[k]];i++){ 
		output[k]=ch[input[k]][i];
		show(k+1,len);
	}	
}

int main(){
	printf("请输入电话号码:\n");
	scanf("%s",input); //输入电话字符数组 
	int len=strlen(input);
	int number[20];
	int sum=1;
	for(int i=0;i<len;i++){
		 input[i]-='0'; //char类型转换成int数组 
		sum*=total[input[i]];
	}
	show(0,len);
	printf("总的组合数:%d\n",sum);
	return 0;
}

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

分析:每个儿子的橘子数目有两种,原有的和现有的,除了老大,其他的儿子原有的+别人给的-给别人的=现有的=平均数,老大是先分给其他人在得到,其他人都是得到再分出去。

算法:If(i=7)

                Return0;

           Elseif(i = 1)

                 x = (420 - y) / 7 * 8;

                 y=x/8;

                 return f(i+1);

          Elseif(i>1)

                  x = 420 * (9 - i) / (8 - i) - y;

                  y = (x + y) / (9 - i);

                  return f(i+1);

代码实现:

#include <stdio.h>
#include "iostream"
using namespace std;
 
//x表示每个人手里的橘子数,y表示从别人那得到的橘子数 ,老六分给老大210个橘子 
int x  ,y = 210;  
int Number(int i)
{
	if(7 == i)
	{
	}
	else if(1 == i) //老大是先分出去再得到 
	{
		x = (420 - y) / 7 * 8;   //420为老大最后手里的橘子数 
		cout << "老大原本有" << x << "个橘子。" << endl;
		y = x / 8;   //计算老大分出去的橘子数 
		return Number(i + 1);
	}
	else if(i > 1)  //其他人都是先得到再分出去 
	{
		x =  420 * (9 - i) / (8 - i) - y; //计算手里原本有多少橘子 
		cout << "老" << i << "原本有" <<x << "个橘子。"<< endl;;
		y = (x + y) / (9 - i);  // 计算得到橘子后再分出去的橘子数 
		return Number(i + 1);
	}
	
}
void main()
{
	Number(1);
}

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值