递归算法的练习

一.一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
1.题目分析
经过7个村庄后还剩两只鸭子,每经过一个村庄卖当前鸭子的一半加一只,所以递归体是经过前一个村子的鸭子数除以2再减去1就是到达下一个村子的时候的鸭子数,所以要想求在第一个村子的鸭子数,必须从后往前推。
2.算法构造
当村子数i=0,鸭子数number=2;当村子数0<i<7,经过第i个村子前的鸭子数number=(number+1)*2,在经过第i 个村子时卖的鸭子数m=number/2+1;
3.算法实现
见文件sellduck.c

#include<stdio.h>
/*
 *author:软工1604 徐於敏 16408070731
 *date:2018-11-15
 *description:一个人赶着鸭子去每个村庄卖,每经过一个村子卖去所赶鸭子的一半又一只。这样他经过了七个村子后还剩两只鸭子,问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?	
 *function:sellduck()函数定义了1个全局变量i代表村子的数量,通过递归实现了计算出发时的鸭子数量
 *version:0.1
 */

int	number=2;//最后的鸭子数量
int m;//用来记录经过每个村子卖出的鸭子数量
int main()
{
	sellduck(7);
}


int sellduck(int i)
{
	
	if(0==i)//i为0时候结束
	{
		printf("他出发时一共赶了%d只鸭子",number);
	}
	else{
		number=(number+1)*2; //计算在经过第i个村子前的鸭子数number 	
		m=number/2+1; //计算在经过第i 个村子时卖的鸭子数m	 	
		printf( "经过第%d个村子时,他卖出%d只鸭子。\n",i,m);
		i--;//村子数量-1
		return sellduck(i); 
	}
}



4.运行结果
在这里插入图片描述

二.角谷定理。输入一个自然数,若为偶数,则把它除以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,是奇数乘以3加1,如此反复调用自身,每做完一次步数+1,并输出此时的数字,最后得到得到的数字为1,此时递归结束
2.算法实现
见solvejiaogu.c

#include<stdio.h>
/*author:软工1604 徐於敏 16408070731 
 *date:2018-11-15
 *description:.角谷定理。输入一个自然数,若为偶数,则把它除以2,若为奇数,则把它乘以3加1。
 *经过如此有限次运算后,总可以得到自然数值1。求经过多少次可得到自然数1。
 *function:定义一个solve()函数,n代表一开始输入的自然数,step代表步数,通过递归实现角谷定理
 *version:0.1
 */

int main()
{	
	int a;
	printf("输入一个自然数:");
	scanf("%d",&a);
	solve(a,1);
	
}

int solve(int n,int step)
{
	
	if(n%2==0){//判断是否为偶数,是偶数除以2
		n=n/2;
		printf("%d\n",n);
		step++;//步数+1
	}
	else {//否则是奇数,将他乘以3加1
		n=n*3+1;
		printf("%d\n",n);
		step++;//步数+1
	}
	if(n==1){
		printf("总的步数是%d次",step);
	}
	if(n!=1){//若当前得到的数字为1,结束递归,否则继续
		solve(n,step);
	}
}

3.运行结果
在这里插入图片描述

三.电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。
1.题目分析
2对应ABC,3对应DEF,4对应GHI,5对应JKL,6对应MNO,7对应PQRS,8对应TUV,9对应WXYZ,1和0对应空。
2.算法构造
当输入一个数字时,返回这个数字所有可能性的组合。递归体是当输入一串数字,每个数字代表不同的字符串,返回最后一个数字跟前面已产生的字符串进行组合,所以首先应该建一个数组,用来存放每个数字代表的字符串组合,然后在建一个数组,用来存放每个字符串的长度,在函数中,先进行判断是否是最后一位,然后根据判断执行函数。
3.算法实现
见phone.cpp

/*
 *author:软工1604 徐於敏 16408070731
 *date:2018-11-15
 *description:电话号码对应的字符组合:在电话或者手机上,一个数字如2对应着字母ABC,7对应着PQRS。那么数字串27所对应的字符的可能组合就有3*4=12种(如AP,BR等)。现在输入一个3到11位长的电话号码,请打印出这个电话号码所对应的字符的所有可能组合和组合数。
 *function:通过递归函数tellphone实现
 *version:0.1
 */

#include<iostream>
using namespace std;


char* phone[10]={"","","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};//数组phone用来存放数字对应的字母
int num[10]={0,0,3,3,3,3,3,4,3,4};//数组num用来存放每一个数字对应的字母的数量
char input[15];//数组input存放输入的电话号码
char output[15];//数组ouput存放输出的组合



void tellphone(int n,int len)
{
    if(n == len)
    {
        cout<<output<<endl;
    }
    for(int i=0; i<num[input[n]]; i++)
    {
        output[n] = phone[input[n]][i];
        tellphone(n+1,len);
    }
}
int main()
{
	int len;
	printf("输入一个3到11位长的电话号码:");
    scanf("%s",input);
	printf("该电话号码所对应字符的所有可能的组合是:\n");
    len=strlen(input);//统计输入的电话号码的长度
    int count = 1;
    for(int i=0; i<len; i++)//计算组合数量 
    {
        input[i] -= '0';
        count *= num[input[i]];
    }
    tellphone(0,len);//调用函数
    cout<<"组合数:"<<count<<endl;///输出组合数量
    return 0;
}

3.运行结果
在这里插入图片描述

四.日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?
1.题目分析
每个儿子拿到的橘子数目分别是原有的和现有的,除了老大,其他的儿子原有的+别人给的-给别人的=现有的=平均数,所以,可以得出原有的=现有的+给别人的-别人给的。
2.算法构造
当老几n>6,结束;当0<n<6时,算出分给下一个人的桔子数,下一个人的桔子数,下一人加上之前的桔子数的总数,接着一个个调用实现
3.算法实现
见orange.cpp

/*
 *author:软工1604徐於敏16408070731
 *date:2018-11-15
 *description:日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完 后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子?
 version:0.1
 */
#include<iostream>
using namespace std;


int orange(int n,int before, int after,int m )//n是老几,before是之前的数量,after是之后的数量,m是从八分之一开始的分桔子的比例
{
	if(n>6)//结束条件
	{
		return 0;
	}
	else
	{
		printf("老%d原有的桔子数:%d\n",n,before);
		int givenum = after/m;//分给下一个人的桔子数
		int nextBnum = 420*(m-1)/(m-2)-givenum;//下一个人的桔子数
		int afterGetnum = nextBeforenum+givenum;//下一人加上之前的桔子数的总数
		return orange(n+1,nextBeforenum,afterGetnum,m-1);
	}
}
int main()
{
	orange(1,240,240,8);
}```

 4.运行结果
  ![在这里插入图片描述](https://img-blog.csdnimg.cn/20181117154556919.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTIyMDgzMw==,size_16,color_FFFFFF,t_70)




五.归纳总结
递归的解决首要就是,找到递归体和递归出口,将大问题分解成小问题,将小问题分解成可以直接解决的问题,在往上推,最终解决问题。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值