[编程题]14、蟠桃记

目录

前言:

1、题目展示:

2、问题分析:

 3、最佳解法展示:


前言:

开新专栏了,讲解100道基础语法编程题

用c语言讲解

目的是复习c语言中的基础语法,为单片机中的c语言代码分析做铺垫

专栏链接:

c语言基础语法编程题_1zero10的博客-优快云博客

1、题目展示:

2、问题分析:

本题最关键的点就在于这句话:

第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。 聪明的你,请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢?

已知从第一天到第n天最后剩1个桃子,求最开始有几个桃,这个问题是数学中的逆向递推等比数列问题

我们分析的时候要搞清楚,每一项到底是什么

在本题中

我们假设第一天没吃桃子之前,桃子总数为第一项

然后第二项是,第一天吃完剩下的桃子数

第三项是,第二天吃完剩下的桃子数

以此类推

第n项是,第n-1天吃完剩下的桃子数,为1

然后我们开始逆向递推寻找规律

以下内容我用纸写下来,方便大家理解

 

 下面我们来演示第一种方法,利用循环实现逆推过程

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
        int n;//第n天
        while (scanf("%d", &n) == 1) {
                int sum = 1;//第n天剩的1个桃
                for (int i = 1;i <= n - 1;++i) {
                        sum = (sum + 1) * 2;
                }
                printf("%d\n", sum);
        }

        return 0;
}

主要解释第8行的意思:

由上面两张图可知,

逆推的逻辑就是每次把上一次的桃子个数,执行先加1再乘以2的操作

下面是第二种方法:直接一开始桃的总数与第n天之间的关系,用公式计算

 

公式法的方法1:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <math.h>
int main() {
        int n;//第n天
        while (scanf("%d", &n) == 1) {
                double x = 3.0 * pow(2, n - 1) - 2;
                printf("%.0lf\n", x);//结果不显示小数点
        }
        return 0;
}

 注意:pow函数的返回值是double类型!切要包含头文件

公式法的方法2:

由于是以2为底数的指数,所以可以用左移运算符!,左移多少就表示2的几次方

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        int x = (3 << (n - 1)) - 2;  // 正确3*(n-1) + 减2,注意运算的先后顺序
        printf("%d\n", x);
    }
    return 0;
}

 

 3、最佳解法展示:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
        int n;//第n天
        while (scanf("%d", &n) == 1) {
                int sum = 1;//第n天剩的1个桃
                for (int i = 1;i <= n - 1;++i) {
                        sum = (sum + 1) * 2;
                }
                printf("%d\n", sum);
        }

        return 0;
}

 

### 问题解析 “孙悟空吃蟠桃”是一道经典的二分查找算法题,目标是找到孙悟空能在H小时内吃完所有桃子的最小速度K。此问题可以通过二分查找来优化求解过程[^1]。以下是详细的解题思路和代码实现。 --- ### 解题思路 1. **确定搜索范围** - 最小速度为1(因为速度不能为0),最大速度为所有桃树中最多的蟠桃数量的最大值。因此,搜索范围为 `[1, max(peaches)]`。 2. **验证中间速度是否可行** - 对于某个速度 `mid`,计算在该速度下需要的时间总和。如果总时间小于等于H,则说明速度 `mid` 是可行的,尝试寻找更小的速度;否则,尝试更大的速度。 3. **二分查找** - 使用二分查找不断缩小搜索范围,直到找到满足条件的最小速度K。 4. **特殊情况处理** - 如果任何速度都无法满足在H小时内吃完所有桃子,则返回0。 --- ### Python代码实现 ```python def min_eating_speed(peaches, H): # 定义检查函数,判断以speed速度是否可以在H小时内吃完所有桃子 def can_finish(speed): hours = 0 for p in peaches: hours += (p + speed - 1) // speed # 向上取整 return hours <= H # 确定二分查找的左右边界 left, right = 1, max(peaches) result = 0 while left <= right: mid = (left + right) // 2 if can_finish(mid): result = mid right = mid - 1 # 尝试寻找更小的速度 else: left = mid + 1 # 增大速度 return result if result > 0 else 0 # 测试用例 peaches = [3, 6, 7, 11] H = 8 print(min_eating_speed(peaches, H)) # 输出结果为4 ``` --- ### Java代码实现 ```java import java.util.Arrays; public class MonkeyEatingPeaches { public static int minEatingSpeed(int[] peaches, int H) { // 定义检查函数,判断以speed速度是否可以在H小时内吃完所有桃子 java.util.function.IntPredicate canFinish = speed -> { int hours = 0; for (int p : peaches) { hours += (p + speed - 1) / speed; // 向上取整 } return hours <= H; }; // 确定二分查找的左右边界 int left = 1, right = Arrays.stream(peaches).max().getAsInt(); int result = 0; while (left <= right) { int mid = left + (right - left) / 2; if (canFinish.test(mid)) { result = mid; right = mid - 1; // 尝试寻找更小的速度 } else { left = mid + 1; // 增大速度 } } return result > 0 ? result : 0; } public static void main(String[] args) { int[] peaches = {3, 6, 7, 11}; int H = 8; System.out.println(minEatingSpeed(peaches, H)); // 输出结果为4 } } ``` --- ### C++代码实现 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int minEatingSpeed(vector<int>& peaches, int H) { // 定义检查函数,判断以speed速度是否可以在H小时内吃完所有桃子 auto canFinish = [&](int speed) -> bool { long long hours = 0; for (auto p : peaches) { hours += (p + speed - 1) / speed; // 向上取整 } return hours <= H; }; // 确定二分查找的左右边界 int left = 1, right = *max_element(peaches.begin(), peaches.end()); int result = 0; while (left <= right) { int mid = left + (right - left) / 2; if (canFinish(mid)) { result = mid; right = mid - 1; // 尝试寻找更小的速度 } else { left = mid + 1; // 增大速度 } } return result > 0 ? result : 0; } int main() { vector<int> peaches = {3, 6, 7, 11}; int H = 8; cout << minEatingSpeed(peaches, H) << endl; // 输出结果为4 return 0; } ``` --- ### JavaScript代码实现 ```javascript function minEatingSpeed(peaches, H) { // 定义检查函数,判断以speed速度是否可以在H小时内吃完所有桃子 function canFinish(speed) { let hours = 0; for (let p of peaches) { hours += Math.ceil(p / speed); // 向上取整 } return hours <= H; } // 确定二分查找的左右边界 let left = 1, right = Math.max(...peaches); let result = 0; while (left <= right) { let mid = Math.floor((left + right) / 2); if (canFinish(mid)) { result = mid; right = mid - 1; // 尝试寻找更小的速度 } else { left = mid + 1; // 增大速度 } } return result > 0 ? result : 0; } // 测试用例 let peaches = [3, 6, 7, 11]; let H = 8; console.log(minEatingSpeed(peaches, H)); // 输出结果为4 ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值