第九天:糖果游戏

每日一道C++题:糖果游戏

问题:某幼儿园里,有5个小朋友编号为1、2、3、4、5,他们按自己的编号顺序围坐在一张圆桌旁。他们身上都有若干个糖果(键盘输入),现在他们做一个分糖果游戏。从1号小朋友开始,将自己的糖果均分三份(如果有多余的糖果,则立即吃掉),自己留一份,其余两份分给他的相邻的两个小朋友。接着2号、3号、4号、5号小朋友同样这么做。问一轮后,每个小朋友手上分别有多少糖果。
要求:输入5个小朋友的糖果数;输出游戏后5个小朋友的糖果数。(按5位宽度输出)。

  1. 数据存储:
  • 使用一个数组 candies[5] 来存储 5 个小朋友的糖果数,数组下标 0 - 4 分别对应小朋友 1 - 5(或者也可以调整下标对应关系,只要处理相邻逻辑正确即可,这里为了方便,假设下标 0 对应 1 号小朋友,下标 1 对应 2 号小朋友,以此类推 )。
  1. 处理每个小朋友的操作:
  • 对于每个小朋友 i (从 0 到 4 ,对应 1 到 5 号 ),执行以下步骤:
  • 获取该小朋友当前的糖果数 current = candies[i] 。
  • 计算要分的份数:因为要均分成 3 份,所以先处理多余的糖果,即 current = current - (current % 3) (吃掉多余的,使能被 3 整除 )。
  • 每份的糖果数 per = current / 3 。
  • 该小朋友自己留下 per 个糖果,即 candies[i] = per 。
  • 相邻的两个小朋友分别得到 per 个糖果。需要注意相邻小朋友的下标计算:
  • 对于小朋友 i (下标 ),左边相邻的小朋友下标是 (i - 1 + 5) % 5 (因为是圆桌,1 号左边是 5 号,对应下标计算要处理循环的情况 )。
  • 右边相邻的小朋友下标是 (i + 1) % 5 。
  • 所以,左边相邻小朋友的糖果数增加 per ,右边相邻小朋友的糖果数也增加 per 。
  • 按照 1 号到 5 号的顺序(即数组下标 0 到 4 的顺序 )依次处理每个小朋友。
  1. 输出处理:
  • 处理完一轮后,按照每个数占 5 位宽度的要求输出 5 个小朋友的糖果数。可以使用 printf 的 %5d 格式控制符,或者使用 cout 结合 setw 和 left 等操作符来实现。
#include <iostream>
// 用于 setw 和 left 等操作符,控制输出格式
#include <iomanip> 
using namespace std;

int main() {
    int candies[5];
    // 输入 5 个小朋友的初始糖果数
    for (int i = 0; i < 5; i++) {
        cin >> candies[i];
    }

    // 依次处理每个小朋友(1 号到 5 号,对应下标 0 到 4 )
    for (int i = 0; i < 5; i++) {
        int current = candies[i];
        // 吃掉多余的糖果,使能被 3 整除
        current -= current % 3; 
        int per = current / 3;

        // 自己留下 per 个糖果
        candies[i] = per; 

        // 计算左右相邻小朋友的下标
        int left = (i - 1 + 5) % 5;
        int right = (i + 1) % 5;

        // 相邻小朋友各得到 per 个糖果
        candies[left] += per;
        candies[right] += per;
    }

    // 按 5 位宽度输出每个小朋友的糖果数
    for (int i = 0; i < 5; i++) {
        // 使用 setw(5) 设置输出宽度为 5,left 表示左对齐(默认是右对齐,这里为了前面补空格,也可以不设置 left ,因为右对齐时不足 5 位前面也会补空格 )
        cout << setw(5) << candies[i]<< endl;
    }
    
    return 0;
}

输入初始糖果数:

  • int candies[5]; :定义一个长度为 5 的数组,用于存储 5 个小朋友的糖果数。
  • for (int i = 0; i < 5; i++) { cin >> candies[i]; } :通过循环,依次读取 5 个整数,作为每个小朋友的初始糖果数。

处理每个小朋友的操作:

  • 外层循环 for (int i = 0; i < 5; i++) :依次处理每个小朋友(下标 0 到 4 ,对应 1 号到 5 号 )。
  • int current = candies[i]; :获取当前小朋友的糖果数。
  • current -= current % 3; :计算并吃掉多余的糖果,使剩下的糖果能被 3 整除。例如,如果当前糖果数是 8 , 8 % 3 = 2 ,所以 current = 8 - 2 = 6 ,能被 3 整除。
  • int per = current / 3; :计算每份的糖果数。
  • candies[i] = per; :当前小朋友自己留下 per 个糖果。
  • int left = (i - 1 + 5) % 5; 和 int right = (i + 1) % 5; :计算左右相邻小朋友的下标。这里使用取模运算 % 5 来处理圆桌的循环情况。例如,当 i = 0 (1 号小朋友 )时, left = (0 - 1 + 5) % 5 = 4 (对应 5 号小朋友 ), right = (0 + 1) % 5 = 1 (对应 2 号小朋友 )。
  • candies[left] += per; 和 candies[right] += per; :相邻的两个小朋友分别增加 per 个糖果。

执行过程:
(1)初始糖果数数组 candies = [8, 9, 10, 11, 12] 。
(2) 处理 1 号小朋友(下标 0 ):

  • current = 8 , current % 3 = 2 ,所以 current = 8 - 2 = 6 , per = 6 / 3 = 2 。
  • candies[0] = 2 。
  • 左相邻下标是 4(5 号小朋友 ),右相邻下标是 1(2 号小朋友 )。
  • candies[4] += 2 → 12 + 2 = 14 ; candies[1] += 2 → 9 + 2 = 11 。此时数组变为 [2, 11, 10, 11, 14] 。
    (3)处理 2 号小朋友(下标 1 ):
  • current = 11 , current % 3 = 2 , current = 11 - 2 = 9 , per = 9 / 3 = 3 。
  • candies[1] = 3 。
  • 左相邻下标是 0(1 号小朋友 ),右相邻下标是 2(3 号小朋友 )。
  • candies[0] += 3 → 2 + 3 = 5 ; candies[2] += 3 → 10 + 3 = 13 。此时数组变为 [5, 3, 13, 11, 14] 。
    (4)处理 3 号小朋友(下标 2 ):
  • current = 13 , current % 3 = 1 , current = 13 - 1 = 12 , per = 12 / 3 = 4 。
  • candies[2] = 4 。
  • 左相邻下标是 1(2 号小朋友 ),右相邻下标是 3(4 号小朋友 )。
  • candies[1] += 4 → 3 + 4 = 7 ; candies[3] += 4 → 11 + 4 = 15 。此时数组变为 [5, 7, 4, 15, 14] 。
    (5) 处理 4 号小朋友(下标 3 ):
  • current = 15 , current % 3 = 0 , per = 15 / 3 = 5 。
  • candies[3] = 5 。
  • 左相邻下标是 2(3 号小朋友 ),右相邻下标是 4(5 号小朋友 )。
  • candies[2] += 5 → 4 + 5 = 9 ; candies[4] += 5 → 14 + 5 = 19 。此时数组变为 [5, 7, 9, 5, 19] 。
    (6)处理 5 号小朋友(下标 4 ):
  • current = 19 , current % 3 = 1 , current = 19 - 1 = 18 , per = 18 / 3 = 6 。
  • candies[4] = 6 。
  • 左相邻下标是 3(4 号小朋友 ),右相邻下标是 0(1 号小朋友 )。
  • candies[3] += 6 → 5 + 6 = 11 ; candies[0] += 6 → 5 + 6 = 11 。此时数组变为 [11, 7, 9, 11, 6] 。
    (7)输出结果:按 5 位宽度输出每个数,得到 11 7 9 11 6 ,与题目中的输出样例一致(可能输出样例的显示格式略有不同,但数值是对应的 )。

知识扩展

  1. 数组下标处理:
  • 在处理圆桌相邻问题时,下标计算是关键。通过取模运算 (i - 1 + 5) % 5 和 (i + 1) % 5 ,可以正确得到循环的相邻下标,避免数组越界。这种处理方式在环形数据结构(如圆桌、环形队列等 )的问题中经常用到。
  1. 输出格式控制:
  • 使用 setw(5) 可以设置输出宽度为 5 个字符。需要注意的是, setw 只对紧跟的输出操作有效,所以在循环中每次输出都需要设置。另外,默认情况下, setw 会使输出右对齐,不足宽度时前面补空格,这正好符合题目中“按 5 位宽度输出”的要求。如果需要左对齐,可以结合 left 操作符,例如 cout << setw(5) << left << candies[i]; ,不过效果和右对齐在补空格方面类似,只是数据的位置不同,但对于整数来说,通常右对齐更符合阅读习惯。
  1. 数据修改的顺序:
  • 在处理每个小朋友的糖果分配时,要注意先修改当前小朋友的糖果数( candies[i] = per ),然后再修改相邻小朋友的糖果数。因为如果先修改相邻小朋友的糖果数,当前小朋友的糖果数还未更新,会导致错误的分配。例如,如果先给相邻小朋友增加糖果,再设置当前小朋友的糖果数为 per ,那么当前小朋友的初始糖果数(未修改前的 )会影响相邻小朋友的分配,而不是已经处理过(吃掉多余糖果后 )的正确数值。
  1. 拓展到更多小朋友的情况:
  • 如果题目中的小朋友数量不是 5 个,而是更多,比如 n 个,那么可以将数组长度改为 n ,并在处理相邻下标时,将取模运算中的 5 改为 n ,这样就可以扩展代码来处理任意数量小朋友围坐圆桌的类似问题。
  • 只需将循环条件改为 for (int i = 0; i < n; i++) ,体现了代码的可扩展性。除了 for 循环,也可用 while 或 do-while 实现。
  • 还可以使用动态数组(如 vector ):vector 是 C++ 中更灵活的动态数组,自动管理内存,适合处理数量不确定的场景。
#include <vector>
int main() {
    int n;
    cin >> n; // 输入小朋友数量
    vector<int> candies(n);
    for (int i = 0; i < n; i++) {
        cin >> candies[i];
    }
    // 后续逻辑类似,只需将 5 替换为 n
    return 0;
}
  1. 环形数据结构的通用处理
  • 除了“圆桌小朋友”,环形队列、循环链表、约瑟夫环问题等都涉及环形结构。
  • 下标计算用 (i ± offset + n) % n ,其中 n 是总数量, offset 是偏移量(如本题中 offset = 1 表示相邻 )。例如:约瑟夫环问题中,计算下一个出局者的下标时,常用 (current + step) % n 。
  1. 复杂规则的扩展(如多轮游戏、条件分配)
  • 多轮游戏:若要进行 k 轮,只需在外层加一个循环
 
int rounds = 3; // 假设进行 3 轮
for (int r = 0; r < rounds; r++) {
    for (int i = 0; i < 5; i++) {
        // 原有处理逻辑
    }
}
  • 若规则改为“只有糖果数大于 10 的小朋友才参与分配”,可添加条件判断:
if (candies[i] > 10) {
    // 原有分配逻辑
} else {
    // 不分配,保持糖果数不变
}
  • 边界情况:
    输入为 0 或负数:题目中说“若干个糖果”,但实际代码未处理负数。可添加条件 。
 if (candies[i] < 0) candies[i] = 0; 

糖果数无法被 3 整除的极端情况(如 1 ): current -= current % 3 会将其变为 0 ,需确保规则允许(题目中“吃掉多余的”是允许的 )。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值