《算法分析与设计》练习3

目录

A 超级青蛙

B 汉诺塔

C 汉诺塔2

D kimi的早餐店

E 字母全排列

F 九数组分数


A 超级青蛙

题目描述

一只超级青蛙一次可以跳上1级台阶,也可以跳上2级……它也能够跳上n级台阶。请问,该青蛙跳上一个n级的台阶总共有多少种跳法?

输入

输入一个正整数n表示台阶的数量。

输出

输出总的跳法数。

样例输入 Copy

1

2

样例输出 Copy

1

2

分析:一般来说,要用递归,肯定是有递归表达式的,嘿嘿嘿

          当然递归表达式就是来找规律滴,此题一样,我们来推一推

假设 青蛙跳  的阶数为   n

当  n=1  时     有   1  种跳法

        2                   2

        3                   4

        4                   8

        5                  16 

               ........

有无找到规律,嘿嘿嘿

没错   就是有    2的n-1次方 种跳法

代码实现:c语言

#include<stdio.h>

#include<stdlib.h>

#include <math.h>



int main (){

int n;

while(~scanf("%d",&n)){

    int z=solve(n);

    printf("%d",z);

    printf("\n");

}

return 0;

}



int solve(int n){

return pow(2,n-1);

}

B 汉诺塔

题目描述

使用递归编写一个程序实现汉诺塔问题,要求在输入圆盘数量之后,输出圆盘的移动步骤,输出格式示例如下:

第1步:1号盘从A柱移至B柱

第2步:2号盘从A柱移至C柱

输入

多组测试用例,每组输入一个正整数n,n代表圆盘数量。

输出

每组输出之间有一行空行。

样例输入 Copy

3

分析:汉诺塔问题是一个经典的递归问题,大家应该要牢记于心,背得出

设有A,B,C 三根柱子   所以

 总共是分为了  三步走: 第一步 除了最下面的圆盘,把其他圆盘都放到B柱上

                                      第二步 把剩下的最下面的圆盘 放到 C柱上

                                      第三步 把刚刚在B柱上的圆盘  借助A柱  放到 C柱上

所以尽兴表演一个记事本手写代码

代码实现:c语言

#include <stdio.h>

#include <stdlib.h>

int step=0;

int main ()

{

int n;

while(~scanf("%d",&n)){

hanoi (n,'A','B','C');

step=0;

printf("\n");



}



return 0;

}



void move (int n,char a,char b){

printf("第%d步:%d号盘从%c柱移至%c柱\n",++step,n,a,b);



}

void hanoi (int n,char a,char b,char c){

if(n>0){

hanoi(n-1,a,c,b);

move(n,a,c);

hanoi(n-1,b,a,c);

}

}

C 汉诺塔2

题目描述

用1,2,...,n表示n个盘子,称为1号盘,2号盘,...。号数大盘子就大。经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。我们知道最少需要移动2^64-1次.在移动过程中发现,有的圆盘移动次数多,有的少 。 告之盘子总数和盘号,计算该盘子的移动次数.

输入

包含多组数据,首先输入T,表示有T组数据.每个数据一行,是盘子的数目N(1<=N<=60)和盘号k(1<=k<=N)。

输出

对于每组数据,输出一个数,到达目标时k号盘需要的最少移动数。

样例输入 Copy

2

60 1

3 1

样例输出 Copy

576460752303423488

4

分析:同理,这些都是找规律的题(设 n为圆盘数, s为移动所有圆盘所需的次数,k为第k个圆盘移动的次数(自底向上数))

我们直接来举例:n=3  s=pow(2,3)-1=7   当 k=1  则  次数为  4

                                                                     k=2  则  次数为  2

                                                                     k=3  则  次数为  1

                           n=4  s=pow(2,4)-1=15  当 k=1 则  次数为  8

                                                                  当 k=2 则  次数为  4

                                                                  当 k=3 则   次数为  2

                                                                  当  k=4 则  次数为   1

不难看出 规律很简单   即:2的n-k 次方

代码实现:c语言

#include <stdio.h>

#include <stdlib.h>



int main (){

int t;

int n;

int k;

while(~scanf("%d",&t)){

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

    scanf("%d %d",&n,&k);

    solve(n,k);





    }



}

return 0;

}



void solve (int n,int k){

    long long s=pow(2,n-k);

     printf("%lld",s);

     printf("\n");



}

D kimi的早餐店

题目描述

Kimi开了一家早餐店,这家店的客人都有个奇怪的癖好:他们只要来这家店吃过一次早餐,就会每天都过来;并且,所有人在这家店吃了两天早餐后,接下来每天都会带一位新朋友一起来品尝。

于是,这家店的客人从最初一个人发展成浩浩荡荡成百上千人:1、1、2、3、5……

现在,Kimi想请你帮忙统计一下,某一段时间范围那他总共卖出多少份早餐(假设每位客人只吃一份早餐)。

输入

测试数据包括多组。

每组数据包含两个整数from和to(1≤from≤to≤80),分别代表开店的第from天和第to天。

输出

对应每一组输入,输出从from到to这些天里(包含from和to两天),需要做多少份早餐。

样例输入 Copy

1 2

1 3

2 3

样例输出 Copy

2

4

3

分析:此题也较为简单,直接先用一个for循环把这个数列放到其中,然后再用一个sum加起来即可

直接看代码

代码实现:c语言

#include <stdio.h>

#include <stdlib.h>



int main (){



long long a[200];

int p;

int q;

  a[1]=1;

    a[2]=1;

    for(int i=3;i<=80;i++)

        a[i]=a[i-1]+a[i-2];

while(~scanf("%d %d",&p,&q))

{

    solve (a,p,q);

}



return 0;

}



void solve(long long a[],int p,int q){

long long  sum=0;

for(int i=p;i<=q;i++)

    sum+=a[i];

printf("%lld",sum);

printf("\n");



}

E 字母全排列

题目描述

编写一个程序,使用递归算法输出一个一维字符数组中所有字符的全排列,假设字符都不一样。例如{'a','b','c'}的全排列为(a,b,c), (a,c,b), (b,a,c), (b,c,a), (c,a,b), (c,b,a)

输入

多组测试用例,每组输入一个正整数n(0<n<=26)。

输出

输出从a开始,连续n个字母的全排列,且每组输出之间用空格隔开。

样例输入 Copy

1

2

样例输出 Copy

a

ab

ba

分析:这个题就有点难度了,肯定要用到递归滴,把每一种情况都罗列递归一遍就实现了全排列

设n为要全排列的字母数目

          第一步,  先用一个数组把26个字母存起来再说

          第二步:开始启用递归  递归一次就把n-1,直到n==1则输出

          第三步:开始从n==2进行回调了

           在n==2中,将其n-1的字母和n-2的字母交换, 再次递归,递归完后n==1,输出,再复原倒数第一个和倒数第二个

                   ..............

说白了,就是画一颗递归树就明白了。

具体看代码理解画递归树,要时刻注意n的值。

代码实现:c语言

#include <stdio.h>

#include <stdlib.h>



int main (){



int n;

char a[26];

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

    a[i]='a'+i;

while(~scanf("%d",&n)){

        int length=n;

    digui(a,n,length);



}

return 0;

}







void digui (char a[],int n,int length){

    if(n==1) {

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

            printf("%c",a[i]);

               printf("\n");

    }

    else{

        digui(a,n-1,length);

        for(int i=n-2;i>=0;i--)

        {

            swap(a,i,n-1);

            digui(a,n-1,length);

            swap(a,i,n-1);

        }

    }



}

void swap(char a[],int i,int j){

char temp=a[i];

a[i]=a[j];

a[j]=temp;

}

F 九数组分数

题目描述

1, 2, 3...9 这九个数字组成一个分数,其值恰好为1/3,要求每个数字出现且只能出现一次,如何组合?编写程序输出所有的组合。

输入

输出

输出所有的结果,如果有多个,每条结果占一行。

结果的格式 : xxxx/xxxxx ,按照分子从小到大的顺序输出。

分析:这个题其实和字母全排列很类似,都是对整个递归树来一遍,只不过这个题多了个判断输出,这个题是放数,字母全排列是交换

直接看代码吧

代码分析:c语言

#include <stdio.h>
#include <stdlib.h>
int a[9];
int v[9];
int main (){
   digui(1);
return 0;
}

void digui (int k){
if(k==10) {
    if((a[1]*1000+a[2]*100+a[3]*10+a[4])*3 == a[5]*10000+a[6]*1000+a[7]*100+a[8]*10+a[9] ){
            printf("%d%d%d%d/%d%d%d%d%d\n",a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9]);
            return ;
            }
}
else{
    for(int i=1;i<=9;i++)
    {
        if(v[i]==0){
              a[k]=i;
              v[i]=1;
        digui(k+1);
        v[i]=0;
        }
    }
}
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值