递归

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

1.题目分析:经过七个村子后还剩下2只鸭子,就是到第八个村子时有2只鸭子,要求出发时有多少只鸭子,就必须得知道到第七个村子时有多少只鸭子,又已知每经过一个村子卖去所赶鸭子的一半又多一只,所以第七天有2*(2+1)=6只鸭子,然后在这样推第六天、第五天、第…的鸭子数量,然后就能推算出出发时的鸭子的数量。

2.算法构造:

fun(n)=2               (n=0)

fun(n)= 2*(fun(n-1)+1)    (n>0)

3.算法实现:

#include<stdio.h>

int fun(int n)

{

if(n==0)                     //代表到第八个村子时,有2只鸭子

return 2;

if(n>0)

    return 2*(fun(n-1)+1);

}

void main()

{

printf("出发时共赶%d只鸭子:\n",fun(7));

int i,m=fun(7);          //定义m为在每个村子时鸭子的总数

for(i=1;i<=7;i++)

{

printf("经过第%d个村子卖出的鸭子数:%d\n",i,m/2+1); //经过每个村子时卖出的鸭子数为总数的一半再加一

m=m/2-1;     //每经过一个村子卖剩下的鸭子数就等于下一个村子的鸭子的总数

}

}

 

5.经验总结;从后面倒着推容易推出,但是刚开始在鸭子出发时的总数是254还是510略有纠结。

二. 角谷定理。输入一个自然数,若为偶数,则把它除以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;然后继续判断,定义一个静态变量i来记录次数,直到得到自然数1时结束循环,用递归来实现循环。

2. 算法构造:

3. 算法实现:

#include<stdio.h>

void fun(int n)

{

    static int i=0;

if(n==1) //当输入的数为1时,为递归的出口,输出step为1

{

i++;

printf("%d\n",n);

printf("STEP:%d\n",i);

return;//递归结束

}

else

{

if(n%2==0) //当输入的数为偶数时,先除以2,然后再判断除完的这个数是奇数、偶数或者为1

{

i++;

printf("%d ",n);

n=n/2;

}

else //当输入为奇数时,先乘3加1,然后再判断n

{

i++;

printf("%d ",n);

n=n*3+1;

}

}

fun(n);//n的值已经在上面的计算中改变了,并实现了规模的减小,知道n为1时结束循环,用递归实现循环

}

void main()

{

int n;

printf("请输入一个自然数用来求角谷数:");

scanf("%d",&n);

    fun(n);

}

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

1.题目分析:在这里,递归出口是,当输入的是一个数字时,返回这个数字所有可能性的组合,递归体是当输入一串数字,每个数字代表不同的字符串,返回最后一个数字跟前面已产生的字符串进行组合  

2.算法构造:首先建一个数组,用来存放每个数字代表的字符串组合,然后在建一个数组,用来存放每个字符串的长度,在函数中,先进行判断是否是最后一位,然后根据判断执行函数。  

3.算法实现:

#include<stdio.h>

#include<iostream>

using namespace std;

const char* letter[10]={"","","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};

const int num[10]={0,0,3,3,3,3,3,4,3,4};     //每个键对应的字母个数

char input[11];       

char output[11];

 

void vocab(int m,int l)

{

    if(m==l)

    {

        output[l]='\0';

        cout<<output<<endl;

    }

    for(int j=0; j<num[input[m]]; j++)

    {

        output[m] = letter[input[m]][j];

        vocab(m+1,l);

    }

}

 

void main()

{

int total=1;

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

cin>>input;               //输入数组

    int len=strlen(input);    //测量数组长度

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

    {

        input[i] -= '0';

        total *= num[input[i]];    //总组合数等于每个数字所对应的字母数之积

    }

    vocab(0,len);

    cout<<"所有的组合数为:"<<total<<endl;

}

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

这是一个递归的问题,每个人最后得到的桔子数是一样的也就是2520/6=420(个)
    每一个兄弟原先的桔子都和上一个给他的桔子数有关系,同时有与他给下一个兄弟的桔子是有关系,关键在于他们六个人连接成一个环状互相关联.所以要解决这个问题肯定得先打破这个环.而最特殊的就是老大.其他人都是先得到后给,而老大是先给后得到.又通过老六给了三分之一老大之后和大家一样多,也就是说剩下三分之二是和平均数一样,所以可以计算出老大得到的橘子数是210个.加上老大给出去之后是420个.所以老大给老二八分之一后是210个.所以老大原来有240个.接下来就可以通过递归调用得到每一个人的桔子数了.

1..题目分析

由题目分析可知,每个儿子得到两部分即从父亲开始分配的和从另一个儿子那里得到的,每个人(第一个儿子例外)从得到的桔子里拿出一部分给其他人。所以需要构造两个递归函数。第一个儿子作为出口

2.算法构造

fun(n)=2*(fun(n+1)+2)

3.算法实现

#include <stdio.h>

#define DENOMINATOR_MAX 8 //分母最大值

#define DENOMINATOR_MIN 3 //分母最小值

//a[n][0]表示第n个孩子分出的桔子总数

//a[n][1]表示第n个孩子从父亲那里分到的桔子总数

int Orange(int a[5][2],int n)

{

int average=2520/6;

if (n==0)

{

//第一个孩子从父亲那里分到的桔子总数应为平均数减去最后一个孩子分出去的部分后乘以8/7

a[n][1] = (average-average/(DENOMINATOR_MIN-1))*(DENOMINATOR_MAX-n)/(DENOMINATOR_MAX-1-n);

//第一个孩子分给第二个孩子的桔子数量。

a[n][0] = a[n][1] - (average-average/(DENOMINATOR_MIN-1));

}

else

{

//第n个孩子从父亲那里分到的桔子总数。

a[n][1] = average *(DENOMINATOR_MAX-n)/(DENOMINATOR_MAX-1-n) - Orange(a,n-1);

//第n个孩子分给第n+1个孩子的桔子数量。

a[n][0] = a[n][1] + Orange(a,n-1) - average;

}

return a[n][0];

}

//主函数

void main()

{

int ora[5][2]={{0,0},{0,0},{0,0},{0,0},{0,0}};

Orange(ora,5);

printf("儿子们拿出桔子状况如下所示:\n");

for(int i=0;i<=5;i++){

printf("第%d个孩子出%d个桔子\n",i+1,ora[i][0]);

}

printf("\n");

printf("父亲最初分配桔子状况如下所示:\n");

for(int j=0;j<=5;j++)

printf("第%d个孩子从父亲那里分得%d个桔子\n",j+1,ora[j][1]);

printf("\n");

getchar();

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值