【递归】-C语言 一些题目

本文解析了几道经典的编程挑战题,包括查找未睡醒的猫咪、汉诺塔问题、找零问题、守望者的逃离及爬楼梯问题。文章通过具体代码展示了如何解决这些问题,并附带详细分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        记录一些题目,仅供个人学习用途

一、没睡醒的猫咪

        题目:

        可爱的很胖的猫咪小沁,与它的朋友们一起组成了一个猫咪合唱团。除开小沁之外,合唱团中总共有318只猫咪,编号依次为0~317。其中317只猫咪的音量都是100,剩下可能有一只猫咪因为没睡醒,所以音量只有90;现在我们要找出这只猫咪,或者确认所有猫咪都睡醒了。聪明的小沁每次可以指挥一组连续编号的猫咪发出声音,并记录它们的音量之和。但是猫咪们不是很有耐心,如果你指挥它们发出声音的次数超过18次,那么它们就都会四散跑掉,各自去玩啦。

小沁提供了这一函数int meow(int start, int end);,它的输入是两个猫咪编号startend,它会返回左闭右开区间[start, end)中猫咪的音量之和;如果你输入的猫咪编号不合法,或者累计调用次数已达18次,那么它就会返回-1。你需要完成函数int find_sleepy_cat(int start, int end);,它的输入也是两个猫咪编号startend,它需要返回左闭右开区间[start, end)中没睡醒的那只猫咪的编号;如果这一区间当中所有猫咪都睡醒了,请返回-1

Input

没睡醒的猫咪的编号ii的取值范围是[-10, 330]
如果输入的编号不合法,说明编号0~317的猫咪其实都睡醒了。

Output

输出没睡醒的猫咪的编号;如果所有猫咪都睡醒了,请输出-1

Hint

不需要关心函数int meow(int start, int end);是如何实现的。
建议用递归哦:将猫咪们划分为两组,并分别观察每一组猫咪的音量之和是否偏小,对音量偏小的一组猫咪递归调用函数int find_sleepy_cat(int start, int end);,直至区间[start, end)中只剩下一只猫咪;如果两组猫咪的音量都正常,则说明区间内的全部猫咪都睡醒了。

分析

        这道题要严格的分类讨论,找边界条件。题目多次出现的不合法返回-1,不合法指的就是end<=start(因为区间左闭右开,所以相等也是错的)。当递归到最后发现不是这个解的时候,也是返回-1。(matrix的题要做对真的是要乖乖听他的话呀)当递归到最后发现是这个解的时候,返回start(左闭右开)。是不是这个解以及在不在这个区间都是用meow来判断。

        递归,要将终止条件先放在前面讨论。


#include "meow.h"        

int find_sleepy_cat(int start, int end)
{
    if (end <= start)                            //这里代表了18次以上与不合法输入
        return -1;
    else if (end - start == 1)
        return meow(start, end)==90? start : -1;//遇到死路后我们也需要返回-1 
    else {
        int middle = start + (end - start) / 2;

        if (meow(start, middle)< (middle - start) * 100)
            return find_sleepy_cat(start, middle);
        else if (meow(middle, end) < (end - middle) * 100)
			return find_sleepy_cat(middle, end);
		else
			return -1;
        
    }
}

二、汉诺塔

        他们说这只是递归的入门级别……、

Input

第一行是一个数字t,表示有t个测试用例

接下来的t行每一行是一个数字n,表示初始状态有n个盘子在木桩1上

Output

对于每一个用例,输出完成游戏的所有操作,每个移动操作占一行

Simple Input

1
3

Simple Output

move disk 1 from peg 1 to peg 3
move disk 2 from peg 1 to peg 2
move disk 1 from peg 3 to peg 2
move disk 3 from peg 1 to peg 3
move disk 1 from peg 2 to peg 1
move disk 2 from peg 2 to peg 3
move disk 1 from peg 1 to peg 3

  分析

        要使得第n组在C位置,则第n-1组要在B位置。要实现hanoi(n,a,b,c)就要有:

        1)        hanoi(n-1,a,c,b);        //n-1从A搬到B

        2)        move(n-1,a,c);           //n从A搬到C

        3)        hanoi(n-1,b,a,c);        //n-1从B搬到C

        终止条件:最后到n=1时,类比n的输入恰好只有1时,把唯一一个圆板从A搬到C。

#include<stdio.h>

void move(int n,int a,int b)
{
    printf("move disk %d from peg %d to peg %d\n",n,a,b);
}

void Hanoi(int n,int a,int b ,int c)
{
    if( n==1 )
    {
        move(1,a,c);
    }
    else
    {
        Hanoi(n-1,a,c,b);
        move(n,a,c);
        Hanoi(n-1,b,a,c);
    }
}

int main(){
    int t,n;
    scanf("%d",&t);
    while( t-- != 0 ){
        scanf("%d",&n);
        Hanoi(n,1,2,3);
    } 
    return 0;
}

三、找零问题

        小李是超市的收银员,每当顾客来结账时,他们给的钱往往都多于他们所购物品的实际价格,这时,小李就需要找零给他们。小李是一个很爱思考的人,他想知道在目前的纸币面额情况下(1角、5角、1元、5元、10元、20元、50元、100元),如果每种面额的纸币的数量都是无限的,他要给一个顾客找零N(0<N<100)元有多少种方式(如0.5元有两种方式:5个1角和1个5角)。小李很苦恼这个问题,聪明的你能帮助他吗?

Input

输入包括多组测试用例,通过EOF结束。
每组测试用例包括一行,为一个数N(1<N<100),N为最多包含一位小数的实数。

Output

对于每组测试用例,输出一行,为一个整数,表示找零的方法总数。

Sample Input

0.5
1

Sample Output

2
4

 分析

       这是两个参数的递归题

        用return 1表示一种结果,累加起来得到答案。

#include<stdio.h>
   int maz[8] = {1000,500,200,100,50,10,5,1};
                //0   1   2    3   4  5 6 7
int zhaoqian(int n,int i)
{
    if(i>7)     return 0;                               //终止条件,优化
    if(i==7)    return 1;
    if(n>=0&&n<5)    return 1;
    if(n<0)     return 0;
    while(n<maz[i]) i++; 
    //状态转移方程                      ↓是在这里减的,上面都是判断而已
    return zhaoqian(n,i+1) + zhaoqian(n-maz[i],i);//以700元为例,既要能反复减100(保留100对应                            
}                                                 //的i)又要能从1角开始反复减(保留700元)


int main()
{
    double rmb=0;   
    while(scanf("%lf",&rmb) != EOF)
    {
        printf("%d\n",zhaoqian( rmb*10 ,0));
    }
}

四、守望者的逃离(循环+分类讨论+最优解)

Description

恶魔猎手尤迪安野心勃勃,他背叛了暗夜精灵,率领深藏在海底的娜迦族企图叛变。守望者在与尤迪安的交锋中遭遇了围杀,被困在一个荒芜的大岛上。为了杀死守望者,尤迪安开始对这个荒岛施咒,这座岛很快就会沉下去。到那时,岛上的所有人都会遇难。

守望者的跑步速度为17m/s,以这样的速度是无法逃离荒岛的。庆幸的是守望者拥有闪烁法术,可在1s内移动60m,不过每次使用闪烁法术都会消耗魔法值10点。守望者的魔法值恢复的速度为4点/s,只有处在原地休息状态时才能恢复。

现在已知守望者的魔法初值M,他所在的初始位置与岛的出口之间的距离S,岛沉没的时间T。你的任务是写一个程序帮助守望者计算如何在最短的时间内逃离荒岛,若不能逃出,则输出守望者在剩下的时间内能走的最远距离。注意:守望者跑步、闪烁或休息活动均以秒(s)为单位,且每次活动的持续时间为整数秒。距离的单位为米(m)。

Input

输入包含多个测试数据(以EOF结束),每个测试数据仅一行,包括空格隔开的三个非负整数M, S, T。

0 <= M <= 1000, 1 <= S <= 10^6, 1 <= T <= 300000

Output

对每个测试数据输出两行:

第1行为字符串"Yes"或"No"(区分大小写),即守望者是否能逃离荒岛。

第2行包含一个整数。第一行为"Yes"(区分大小写)时表示守望者逃离荒岛的最短时间;第一行为"No"(区分大小写)时表示守望者能走的最远距离。

Sample Input

39 200 4
36 255 10

Sample Output

No
197
Yes
6

分析

        变化量有三个:距离,时间,蓝。如果我们把时间当成自变量,让它一秒一秒的流逝,将会大大减少讨论的难度。

        主题思路在代码里。

#include<stdio.h>

int main(){
    int M,S,t;            //蓝,距离、限时
    int flash=0,sum=0,i;
    while(scanf("%d%d%d",&M,&S,&t) != EOF)    //用scanf判断EOF
    {
        flash=0;              
        sum=0;                //sum在过程中表示跑步距离,在每次循环的最后会变成最大距离
        for(i=1;i<=t;i++)     //时间按秒流逝,以此做for循环,接下来只需要看路程 
        {                     //思路改成:要么闪或补魔,要么跑步,他们都要花一秒 
            if(M>9)           //如果蓝够,想都不用想,闪现就对了 但实际上闪现的过程是参与
                              //在等蓝的过程中的,因此要将其作为双线并进考量的一部分。
            {    
                M -= 10;
                flash += 60;
            }
            else              //如果蓝不够了,双线并进,同时进行跑步与休息,取最大值
                M+=4;
                
            sum += 17;        //sum保持最优解 ,双线并进就是最优解思想   
            if(sum<flash)   sum = flash;         
            if(sum>=S)  {
                printf("Yes\n%d\n",i);
                break;
            }
	
        }                     //现在离开了循环,要么因为sum够大了,要么因为超时了
        if(i>t)        printf("No\n%d\n",sum);
        
    }
	return 0; 
}

五、爬楼梯70

分析:本质就是斐波那契,但是递归效率低,可用循环从下到上

class Solution {
public:
    int climbStairs(int n) {
        if(n == 1){return 1;}
        if(n == 2){return 2;}
        int a = 1, b = 2, temp;
        for(int i = 3; i <= n; i++){
            temp = a;
            a = b;
            b = temp + b;
        }
        return b;   
    }
};
### C语言递归练习题及其解法 #### 题目一:计算n的k次方 通过递归来实现幂运算功能。以下是完整的代码示例: ```c #include <stdio.h> double Pow(int n, int k) { if (k == 0) { return 1; } else if (k > 0) { return n * Pow(n, k - 1); } else { return 1.0 / (Pow(n, -k)); } } int main() { int n, k; printf("输入底数和指数:"); scanf("%d %d", &n, &k); double result = Pow(n, k); printf("结果:%lf\n", result); return 0; } ``` 上述程序实现了正整数、零以及负整数作为指数的情况处理[^2]。 --- #### 题目二:阶乘计算 利用递归方法来完成阶乘计算的功能,具体如下所示: ```c #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int factorial(int i); int main() { int num; printf("请输入一个需要计算其阶乘的数:"); scanf("%d", &num); printf("结果为:%d\n", factorial(num)); return 0; } int factorial(int i) { if (i == 0 || i == 1) { return 1; } else { return i * factorial(i - 1); } } ``` 该算法展示了如何使用递归解决简单的数学问题,如阶乘计算[^3]。 --- #### 题目三:斐波那契数列 斐波那契数列是一个经典的递归应用案例,定义如下: F(0)=0, F(1)=1, 对于所有的n≥2有F(n)=F(n−1)+F(n−2) 下面是基于递归方式实现斐波那契数列的一个例子: ```c #include<stdio.h> long fibonacci(long number){ if(number==0||number==1) return number; else return(fibonacci(number-1)+fibonacci(number-2)); } int main(){ long result; int input; printf("Enter an integer: "); scanf("%d",&input); result=fibonacci(input); printf("\nThe Fibonacci of the entered integer is :%ld",result); return 0; } ``` 这段代码清晰地体现了递归调用的过程,并且能够正确返回指定位置上的斐波那契数值[^1]。 --- #### 题目四:汉诺塔游戏 这是一个非常著名的递归问题实例之一——汉诺塔(Hanoi Tower),它描述了三个柱子之间移动盘片的游戏规则。下面给出了解决方案的具体实现过程: ```c void hanoi(int n,char src,char dest,char temp){ if(n==1){ printf("Move disk from %c to %c.\n",src,dest); }else{ hanoi(n-1,src,temp,dest); printf("Move disk from %c to %c.\n",src,dest); hanoi(n-1,temp,dest,src); } } int main(){ int disks=3;//可以修改这个变量测试不同数量的圆盘情况 hanoi(disks,'A','C','B'); return 0; } ``` 这里采用分治策略解决了复杂度较高的实际应用场景中的难题[^4]。 --- #### 总结 以上列举了几种常见的C语言递归练习题目及其实现方法,涵盖了基本算术操作、序列生成以及逻辑推理等方面的知识点。对于初学者来说是非常好的实践素材。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值