递归函数的几个例子

来源:互联网 发布:it项目经理成长手记 编辑:程序博客网 时间:2024/05/29 09:47

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

解:

算法分析:第7天卖完剩2只,则第六天卖完剩2*2+1)只,第五天卖完剩2*2*2+1+1)只...依次类推,用Fun7)表示未卖之前的总数,相当于第0个村庄,那么Fun6)表示路过第一个村庄,...依次类推,用F0)表示路过第七个村庄,所以当m=0时,return 2,为该程序的出口。其他情况return 2*Funn-1+1;

程序实现:

#include<stdio.h>

int Fun(int m)

{

if(m==0)

return 2;

else

return 2*(Fun(m-1)+1);

}

void main()

{

int i,n=Fun(7);

printf("鸭子的总数为:%d\n",Fun(7));

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

{

printf("%d天卖出的鸭子数为:%d\n",i,n/2+1); //卖出的鸭子数为前一天剩余的鸭子总数的一半加一

n=n/2-1; //剩余的鸭子数为前一天剩余的鸭子总数的一半减一

}

}


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

如:输入22

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

 STEP=16

解:

算法分析:首先输入一个自然数m,调用函数Fun(int m),m的值传给形参。每次进行判断如果是偶数返回Fun(m/2),是奇数返回Funm*3+1,递归调用Fun()函数,直到m=1的时候,返回1,调用结束。另外为了方便计算步数,可在判断是奇数时,直接返回Fun(m/2)+1,偶数同理。然后利用n=Fun(m),输出n的值即为运算的步数。

程序实现:

#include<stdio.h>

int Fun(int m) //定义m为自然数

{

printf("%4d",m);

if(m==1)

return 1; //m=1的时候返回1

if(m%2==1)

return Fun(m*3+1)+1;//m为奇数,返回它的三倍加1,后面的加一是步数加一

if(m%2==0)

return Fun(m/2)+1; //m为偶数,返回它的一半,同理后面的加一是步数加1

}

void main()

{

int m,n=0;

printf("请输入一个自然数:");

scanf("%d",&m);

n=Fun(m); //定义步数为n,并将m的值传递给形参

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

}


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

解:

算法分析: 把每个数字看成8皇后棋盘中的一行,这一行的内容就是这个数字所对应的字符串。和8皇后问题从每一行选一个列位置类似的,在每一个数字对应的字符串中选一个字符,然后递归找到直到找到一个可能字符数组为止。

代码实现:

#include <stdio.h>

#include <string.h>

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

char num_str[12];  // 储存输入的电话号码所对应的字符串。

char result[12];  // 储存一个可能的字符组合。

char str_idx[12];  // 储存输入的电话号码的数字所对应的字符串在pStr中的索引。

int cnt_zuhe = 0; // 储存可能的字符组合总数。

int num_len; // 储存输入的电话号码的长度。

 

void reverse(char *pstr)

{

    int i = 0, j = strlen(pstr) - 1;

    char tmp;

    while (i < j ) {

        tmp = pstr[i];

        pstr[i] = pstr[j];

        pstr[j] = tmp;

        ++i;

        --j;

    }

}

// 将数字转换为字符串。

int get_num_str(int number, char* str)

{

    int cnt = 0;

    

    do {

        str[cnt++] = (char)(number % 10 + '/0');

    } while (number /= 10);            

    str[cnt] = '/0';

    num_len = cnt;

    reverse(str);

    return cnt;

}

void init_idxs()

{

    int i = 0;

    char *p = num_str;

    while (*p != '0') {

        str_idx[i++] = *p - '0' - 2;

        ++p;

    }

}

bool IsLegal(int i, int j)

{

    if (i < num_len && pStr[str_idx[i]][j] != '/0')

        return true;

    return false;

}

void f(int i)

{

    // i为输入的电话号码中的第i个数字,j为这个数字对应的字符串的第j个字符。

    for (int j = 0; j != 4; ++j) {

        if (IsLegal(i, j)) {  // 取第j个字符。如果索引ij都合法,则把字符加入到结果中。

            result[i] = pStr[str_idx[i]][j];

            if (i == num_len - 1) {

                ++cnt_zuhe;

                printf("%s ", result);

            }

            f(i + 1); // i + 1个数字。

        }

    }

}

int transfer(int number)

{

    num_len = get_num_str(number, num_str);  // 得到电话号码对应的字符串。

    if (num_len < 3 || num_len > 11) // 检查输入是否符合要求。

        return 0;

    char *p = num_str;

    while (*p != '/0') {

        if (*p == '0' || *p == '1')

            return 0;

        ++p;

    }

    init_idxs(); // 计算输入的电话号码的数字所对应的字符串在pStr中的索引。

    f(0); // 从电话号码的第0个数字开始搜索。

    return cnt_zuhe;    

}

int main()

{

   int number;

printf("请输入电话号码:);

     scanf("%d", &number);

printf("所有的组合数为:);

     printf("%d ", transfer(number));

     return 0;

}


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

解:

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

i个孩子分给i+1孩子的桔子数a[i][0]a[i][1] + Fun(a,i-1) - ave,a[i][1]i个孩子从父亲那里分到的桔子总数。循环调用Fun()函数,令p=a[i][0],每执行一次返回p.

程序实现:

#include <stdio.h>

#define MAX 8 //分母最大值为8

#define MIN 3 //分母最小值为3

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

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

int Fun(int a[5][2],int i)

{

int ave=2520/6; //平均值为总数除以6

int p;

if (i==0)

{

a[i][1] = (ave-ave/(MIN-1))*(MAX-i)/(MAX-1-i);      //第一个孩子分给第二个孩子的桔子数量。

a[i][0] = a[i][1] - (ave-ave/(MIN-1));

}

else

{

a[i][1] = ave *(MAX-i)/(MAX-1-i) - Fun(a,i-1); //i个孩子从父亲那里分到的桔子总数

a[i][0] = a[i][1] + Fun(a,i-1) - ave; //i个孩子分给第i+1个孩子的桔子数量

}

p=a[i][0];

return p;

}

void main()

{

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

Fun(orange,5);

printf("儿子们拿出桔子数为:\n");

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

printf("%d个孩子出%d个橘子\n",j+1,orange[j][0]);

printf("\n");

printf("父亲最初分配桔子数为:\n");

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

printf("%d个孩子从父亲那里分得%d个橘子\n",k+1,orange[k][1]);

getchar();

}




原创粉丝点击