当前位置: 首页 > news >正文

洛谷 P1427 小鱼的数字游戏

洛谷 P1427 小鱼的数字游戏

恩师:hnjzsyjyj

一、题目介绍:初识小鱼的数字游戏

大家好呀!今天咱们要一起学习的是洛谷上的一道入门级编程题 ——P1427 小鱼的数字游戏。这道题虽然简单,但对于刚接触编程的小伙伴来说,是理解 “输入处理”“数据存储” 和 “循环输出” 的绝佳案例。咱们先从题目本身开始,一步步揭开它的面纱~

1.1 题目来源与定位

洛谷 P1427 是洛谷题库中的一道入门级题目,难度评级为 “入门”,非常适合刚开始学习 C++ 编程的同学练习。它主要考察的是对基本输入输出、循环结构和数组使用的掌握程度,是很多小伙伴在编程路上遇到的 “小甜点” 题目~

1.2 题目描述

咱们先来看题目到底要我们做什么(虽然题目名叫 “小鱼的数字游戏”,但其实和游戏关系不大,更像是一个数字处理任务哦):

题目要求我们实现一个程序,这个程序需要完成以下操作:

  • 首先,持续接收用户输入的整数,这些整数可以是正数、负数(但题目里没说限制,不过实际输入都是整数啦);
  • 当输入的整数是 “0” 时,就停止接收输入;
  • 最后,把之前输入的所有整数(注意哦,不包括最后那个 “0”)按照倒序的方式输出出来,每个数之间用空格隔开。

举个例子方便大家理解:如果输入的是 “3 1 2 0”,那么输出就应该是 “2 1 3”;如果输入的是 “5 0”,输出就是 “5”;如果输入的第一个数就是 “0”,那输出就什么都没有(因为没有有效数字呀)。

是不是很清晰?这道题的核心就是 “接收输入→存储数据→倒序输出”,听起来不难,但里面藏着不少编程的基础知识点,咱们慢慢聊~

1.3 题目难度与适合人群

这道题的难度属于 “入门级”,适合刚学完 C++ 基础语法(变量、循环、数组)的小伙伴练习。如果你刚学会怎么用cin输入、cout输出,知道数组怎么定义和访问,那这道题对你来说刚刚好~ 就算你还不太熟练也没关系,跟着我一步步分析,保证你能学会!

二、解题思路:拆解问题的三步法

面对一道编程题,咱们可不能上来就写代码,得先想清楚 “怎么做”。就像盖房子要先画图纸,解题目也得先有思路~ 对于 “小鱼的数字游戏”,咱们可以把问题拆成三个关键步骤:

2.1 第一步:处理输入 —— 怎么接收用户的数字?

题目要求 “持续接收整数,直到输入 0 为止”,这就意味着我们需要一个循环结构来反复读入数字。那用什么循环呢?C++ 里有while循环、for循环,这里用while循环最方便,因为我们不知道要输入多少个数,直到遇到 “0” 才停止,属于 “条件终止” 的循环。

那循环里要做什么呢?每次循环都要读入一个整数,然后判断这个整数是不是 “0”:

  • 如果是 “0”,就跳出循环,结束输入;
  • 如果不是 “0”,就把这个数存起来,留着后面用。

这一步的核心是 “循环读入 + 终止条件判断”,大家可以记一下这个思路,以后遇到 “持续输入直到某个条件停止” 的问题,都可以用这个方法~

2.2 第二步:存储数据 —— 用什么装这些数字?

输入的数字不能用完就丢呀,咱们后面还要倒序输出呢,所以得找个 “容器” 把它们存起来。在 C++ 里,最常用的 “容器” 就是数组啦!数组就像一个有很多格子的盒子,每个格子可以装一个数字,而且每个格子都有自己的编号(也就是数组下标),方便我们后续查找和使用。

那数组要定义多大呢?题目里没明确说输入的数字最多有多少个,但洛谷的入门题一般不会卡数据范围,咱们可以定义一个稍微大一点的数组,比如a[105](表示能装 105 个数字),足够应对这道题的所有测试数据了。

除了数组,我们还需要一个 “计数器” 来记录到底存了多少个有效数字(因为最后要倒序输出,得知道有多少个数要输出呀)。这里可以用一个变量id,每次存一个数字,id就加 1,这样最后id的值就是有效数字的个数啦~

2.3 第三步:倒序输出 —— 怎么把数字反过来?

存好数字后,最后一步就是把它们倒序输出。假设我们存了id个数字,分别存在数组的a[1]a[id](这里注意数组下标从 1 开始哦,方便计数),那倒序输出就是从最后一个数字a[id]开始,依次输出a[id-1]a[id-2]…… 直到a[1]

怎么实现这个过程呢?用一个for循环就可以啦!循环的变量iid开始,每次减 1,直到i等于 1 为止,在循环里依次输出a[i],每个数后面加个空格,这样就完成倒序输出啦~

总结一下解题的三步法:循环输入并判断终止条件→用数组存储有效数字→反向遍历数组输出。是不是很清晰?接下来咱们就根据这个思路,看看具体的代码怎么写~

三、代码解析:逐行读懂小鱼的游戏代码

接下来就是大家最关心的代码部分啦!咱们直接用题目里给的代码,逐行分析它是怎么实现上面的解题思路的。先把代码贴出来,大家可以先眼熟一下:

cpp

#include<bits/stdc++.h>
using namespace std;
int a[105],id,x; 
int main() {while(cin>>x){if(x==0)break;a[++id]=x;}for(int i=id;i>=1;i--)cout<<a[i]<<" ";return 0;
}

这短短的几行代码,就完成了小鱼的数字游戏的所有功能,咱们一步步来看~

3.1 头文件与命名空间:代码的 “开胃菜”

cpp

#include<bits/stdc++.h>
using namespace std;

这两行是 C++ 代码的 “标配开头”,咱们来解释一下:

  • #include<bits/stdc++.h>:这是一个 “万能头文件”,它包含了 C++ 中几乎所有常用的标准库(比如输入输出库、数组库、字符串库等)。有了它,咱们就不用一个个写#include<iostream> #include<vector>这些头文件了,非常方便,尤其适合写短代码的时候用~不过要注意哦,在一些严格的比赛中可能不推荐用万能头文件,但入门练习用它完全没问题!

  • using namespace std;:这句话的意思是 “使用标准命名空间”。C++ 里很多常用的函数(比如cin cout)都在std这个命名空间里,如果不写这句话,每次用cin就得写成std::cin,会很麻烦。加上这句话后,咱们就可以直接用cin cout啦,简化代码~

3.2 变量定义:给数字找 “家”

cpp

int a[105],id,x; 

这行代码定义了三个变量,咱们分别来看:

  • int a[105]:定义了一个名叫a的数组,它是int类型(用来存整数),大小是 105(也就是说最多能存 105 个整数)。前面咱们说过,这个数组就是用来存输入的有效数字的 “盒子”。

  • int id:这个变量是 “计数器”,用来记录输入的有效数字的个数。一开始id的值是 0,每存一个有效数字,id就加 1,最后id的值就是数字的总个数。

  • int x:这个变量是 “临时容器”,用来暂时存储每次输入的整数,方便我们判断这个数是不是 0,以及要不要存到数组里。

这里有个小细节:数组a的大小为什么是 105 呢?因为题目中输入的数字个数不会太多(洛谷的入门题一般数据范围很小),105 足够用了。如果担心不够,也可以定义成a[1005],多留点空间总没错~

3.3 主函数:程序的 “心脏”

C++ 程序的执行都是从main函数开始的,咱们重点来看main函数里的代码:

3.3.1 输入处理:while循环读入数字

cpp

while(cin>>x){if(x==0)break;a[++id]=x;
}

这几行代码实现了 “持续输入直到遇到 0” 的功能,咱们逐句分析:

  • while(cin>>x)cin>>x的意思是 “从输入设备(比如键盘)读一个整数到变量 x 里”,这个操作本身会返回一个 “是否读取成功” 的状态。while循环的条件就是 “只要能成功读入 x,就继续循环”,这样就能持续接收输入啦~

  • if(x==0)break;:这是循环里的终止条件。当读入的 x 是 0 时,就执行break,跳出整个while循环,结束输入过程。这里要注意哦,0 是不存到数组里的,它只是一个 “停止信号”。

  • a[++id]=x;:这行是存储有效数字的关键!++id是 “前置自增” 操作,意思是先把id的值加 1,再用加 1 后的id作为数组的下标。比如第一次输入有效数字时,id原本是 0,++id后变成 1,所以a[1] = x,把第一个数字存到数组的第 1 个位置;第二次输入时,id变成 2,a[2] = x,以此类推。这样数组的a[1]a[id]就依次存了所有有效数字,非常整齐~

这里有个小疑问:为什么不用id++呢?如果写成a[id++]=x,第一次输入时id是 0,会先把 x 存到a[0],然后id变成 1,这样数组的下标就从 0 开始了。倒序输出时也可以,但用++id让下标从 1 开始,更符合我们 “第 1 个、第 2 个” 的计数习惯,后续输出时逻辑更清晰~

3.3.2 倒序输出:for循环反向遍历

cpp

for(int i=id;i>=1;i--)cout<<a[i]<<" ";

这行代码实现了倒序输出的功能,咱们来拆解一下:

  • for循环的格式是for(初始条件;循环条件;更新操作)。这里初始条件是i=id(从最后一个有效数字的下标开始);循环条件是i>=1(只要 i 大于等于 1,就继续循环);更新操作是i--(每次循环后 i 减 1,往前移动一个位置)。

  • cout<<a[i]<<" ":在循环里,每次输出数组a中第i个位置的数字,然后输出一个空格,这样每个数字之间就有空格隔开啦~

举个例子:如果输入的数字是 3、1、2,那么id最后是 3,数组a[1]=3a[2]=1a[3]=2for循环中 i 从 3 开始,先输出a[3]=2,然后 i=2,输出a[2]=1,再 i=1,输出a[1]=3,最后结果就是 “2 1 3”,完美实现倒序输出~

3.3.3 程序结束:return 0

cpp

return 0;

这行代码表示main函数执行结束,程序正常退出。在 C++ 里,main函数的返回值 0 通常表示 “程序成功执行完毕”。

四、易错点分析:这些坑千万别踩!

虽然这道题看起来简单,但刚开始编程的小伙伴很容易在细节上出错。咱们来盘点一下常见的易错点,帮大家避避坑~

4.1 易错点 1:数组下标越界或存储错误

问题描述:

有的小伙伴可能会把数组的下标搞混,比如用a[id++] = x,结果第一个数字存在a[0],最后倒序输出时漏掉第一个数;或者数组定义太小,比如a[10],但输入了 11 个数字,导致数组越界,程序崩溃。

例子:

错误代码:

cpp

int a[10],id=0,x;
while(cin>>x){if(x==0)break;a[id++]=x; // 这里用了id++,下标从0开始
}
for(int i=id;i>=1;i--)cout<<a[i]<<" "; // 循环从id开始,会漏掉a[0]

这个代码中,数组下标从 0 开始存,但输出时从id(此时id是数字个数)开始,而a[id]是没有存数据的,导致输出错误。

解决办法:
  • 统一数组下标从 1 开始:用++id作为下标,确保第一个数字存在a[1],最后一个在a[id]
  • 数组定义大一点:比如a[105]a[1005],避免数据太多存不下。

4.2 易错点 2:忘记处理 0 的输入

问题描述:

有的小伙伴可能会把 0 也存到数组里,导致输出时多了一个 0;或者没判断 0 的输入,让循环一直执行,停不下来。

例子:

错误代码:

cpp

while(cin>>x){a[++id]=x; // 没有判断x是否为0,直接存起来if(x==0)break;
}

这个代码会把 0 存到数组里,最后输出时会多一个 0,不符合题目要求(0 是终止信号,不输出)。

解决办法:

一定先判断 x 是否为 0,只有 x 不是 0 时才存到数组里,顺序不能反:if(x==0)break;要写在a[++id]=x;前面。

4.3 易错点 3:输出格式错误

问题描述:

题目要求每个数字之间用空格隔开,但有的小伙伴可能最后多输出一个空格,或者忘记加空格,导致格式错误。

例子:

错误代码 1(没加空格):

cpp

for(int i=id;i>=1;i--)cout<<a[i]; // 输出结果连在一起,比如“213”

错误代码 2(多一个空格):

cpp

for(int i=id;i>=1;i--)cout<<a[i]<<" "; 
// 最后会多一个空格,比如“2 1 3 ”(洛谷一般不卡这个,但严格来说不规范)
解决办法:
  • 必须加空格:每个数字后面加空格,确保数字之间分开(洛谷的评测系统对末尾多的空格通常不严格,不用太担心)。
  • 规范写法:如果担心末尾空格,可以先输出第一个数,再循环输出 “空格 + 数字”,比如:

cpp

if(id>=1)cout<<a[id]; // 先输出最后一个数
for(int i=id-1;i>=1;i--)cout<<" "<<a[i]; // 再输出空格+前面的数

4.4 易错点 4:循环条件错误

问题描述:

输出时的for循环条件写错,比如写成i>0i>=1虽然效果一样,但有的小伙伴可能写成i<id,导致循环次数不对。

例子:

错误代码:

cpp

for(int i=id;i>id;i--)cout<<a[i]<<" "; // 循环条件错误,循环一次都不执行

这个代码的循环条件i>id永远不成立,导致什么都不输出。

解决办法:

输出循环的条件必须是 “从 id 开始,到 1 结束”,即i>=1i>0,确保每个有效数字都被输出。

4.5 易错点 5:输入方式导致的问题

问题描述:

有的小伙伴用scanf输入,但没处理好输入失败的情况;或者用cin时没注意输入格式,导致循环异常。

例子:

错误代码:

cpp

int x;
while(x!=0){ // 没先输入x就判断,x的初始值不确定cin>>x;a[++id]=x;
}

这个代码中,第一次判断x!=0时,x 还没被赋值,值是不确定的,可能导致循环一开始就不执行。

解决办法:

while(cin>>x)的形式,先输入 x,再判断是否为 0,确保循环逻辑正确。

五、优化方向:让代码更优雅

咱们现在的代码已经能正确解决问题了,但还可以从几个角度优化,让代码更简洁、更灵活~

5.1 优化 1:用vector替代数组(动态存储)

咱们现在用的是固定大小的数组,虽然够用,但如果输入的数字特别多,数组大小可能不够。C++ 中的vector(向量)是一种动态数组,可以自动调整大小,更灵活~

优化代码:

cpp

#include<bits/stdc++.h>
using namespace std;
vector<int> a; // 定义一个vector,不用指定大小
int x; 
int main() {while(cin>>x){if(x==0)break;a.push_back(x); // 把x添加到vector末尾}for(int i=a.size()-1;i>=0;i--)cout<<a[i]<<" "; // vector下标从0开始return 0;
}
优点:
  • 不用提前定义大小,输入多少数字都能存下,不用担心越界。
  • a.size()直接获取数字个数,不用id计数器,更简洁。

5.2 优化 2:用栈实现倒序(先进后出)

倒序输出的本质是 “先进后出”,而栈(stack)这种数据结构正好满足这个特性:先存进去的数字后出来。

优化代码:

cpp

#include<bits/stdc++.h>
using namespace std;
stack<int> s; // 定义一个栈
int x; 
int main() {while(cin>>x){if(x==0)break;s.push(x); // 把数字压入栈}while(!s.empty()){ // 栈不为空时cout<<s.top()<<" "; // 输出栈顶元素(最后进去的数字)s.pop(); // 弹出栈顶元素}return 0;
}
优点:
  • 不用手动记录数字个数,栈的empty()top()方法直接帮我们处理倒序。
  • 更符合 “倒序” 的逻辑思维,代码可读性强。

5.3 优化 3:输入输出效率提升

对于大量输入输出的情况,cincout的效率可能不够高,这时候可以用scanfprintf,或者给cin/cout提速。

提速代码:

cpp

#include<bits/stdc++.h>
using namespace std;
int a[105],id,x; 
int main() {ios::sync_with_stdio(false); // 关闭cin与stdio的同步,提速cin.tie(0); // 解除cin和cout的绑定,进一步提速while(cin>>x){if(x==0)break;a[++id]=x;}for(int i=id;i>=1;i--)cout<<a[i]<<" ";return 0;
}
优点:
  • ios::sync_with_stdio(false);cin.tie(0);能显著提高cin/cout的输入输出速度,在数据量大时很有用。

六、拓展练习:从小鱼游戏到更多倒序问题

学会了小鱼的数字游戏,咱们可以趁热打铁,看看类似的 “倒序” 问题怎么解决,巩固一下知识点~

6.1 拓展练习 1:倒序输出字符串

题目:

输入一个字符串,倒序输出这个字符串(比如输入 “abc”,输出 “cba”)。

思路:
  • string存储字符串;
  • 从字符串的最后一个字符开始,依次输出到第一个字符。
参考代码:

cpp

#include<bits/stdc++.h>
using namespace std;
int main() {string s;cin>>s;for(int i=s.size()-1;i>=0;i--)cout<<s[i];return 0;
}

6.2 拓展练习 2:倒序后计算平均值

题目:

输入若干整数,以 0 结束,倒序输出这些整数后,再输出它们的平均值(保留一位小数)。

思路:
  • 用数组存数字,记录个数id
  • 倒序输出数组;
  • 计算数组中所有数字的和,除以id得到平均值。
参考代码:

cpp

#include<bits/stdc++.h>
using namespace std;
int a[105],id,x; 
double sum=0;
int main() {while(cin>>x){if(x==0)break;a[++id]=x;sum+=x; // 累加求和}// 倒序输出for(int i=id;i>=1;i--)cout<<a[i]<<" ";// 输出平均值cout<<endl<<fixed<<setprecision(1)<<sum/id;return 0;
}

6.3 拓展练习 3:多组测试数据

题目:

有多组测试数据,每组数据都按 “小鱼的数字游戏” 规则输入(以 0 结束),每组数据输出一行倒序结果,直到输入 “-1” 表示所有测试结束。

思路:
  • 用外层循环包裹每组数据的处理;
  • 每组数据开始前重置id和数组,避免和上一组数据混淆。
参考代码:

cpp

#include<bits/stdc++.h>
using namespace std;
int a[105],id,x; 
int main() {while(true){ // 外层循环处理多组数据id=0; // 重置计数器cin>>x;if(x==-1)break; // 所有测试结束if(x==0){ // 本组没有有效数字cout<<endl;continue;}a[++id]=x;while(cin>>x){ // 处理本组其他数字if(x==0)break;a[++id]=x;}// 倒序输出本组结果for(int i=id;i>=1;i--)cout<<a[i]<<" ";cout<<endl;}return 0;
}

七、总结:小鱼游戏带给我们的编程启示

通过学习洛谷 P1427 小鱼的数字游戏,咱们不仅学会了一道题的解法,更掌握了编程中的几个核心知识点:

7.1 循环结构的灵活使用

while循环适合 “条件不确定” 的持续操作,比如 “输入直到某个条件停止”;for循环适合 “已知范围” 的遍历,比如 “从 id 到 1 的倒序输出”。掌握不同循环的适用场景,能让代码更简洁高效。

7.2 数组的基础应用

数组是存储多个同类型数据的基础工具,通过下标访问和遍历数组,是处理批量数据的核心技能。记住数组下标从 0 还是 1 开始,对后续操作至关重要。

7.3 问题拆解的思维

面对任何编程问题,都可以像拆 “小鱼的游戏” 一样,把复杂问题拆成 “输入→存储→输出” 等小步骤,一步步解决。这种 “拆解思维” 能帮我们理清思路,避免无从下手。

7.4 细节决定成败

处理输入时的终止条件、数组下标的正确使用、输出格式的规范,这些细节虽然小,但直接影响程序是否正确。编程中一定要注重细节,多调试、多测试。

八、PPT 展示建议

如果用这篇内容做 PPT,建议按以下结构分页,重点突出,方便讲解:

  1. 封面页:标题 “洛谷 P1427 小鱼的数字游戏”+ 简单背景图
  2. 题目介绍页:题目描述 + 示例输入输出(用大字体展示)
  3. 解题思路页:三步法流程图(输入→存储→输出)
  4. 代码框架页:代码整体结构,标出核心部分
  5. 逐行解析页:分 3-4 页,每页解析 1-2 行代码,重点讲while循环和for循环
  6. 易错点页:用表格列出易错点和解决办法
  7. 优化方向页:对比不同方法的代码(数组 vs vector vs 栈)
  8. 拓展练习页:列出拓展题目,简要说明思路
  9. 总结页:核心知识点提炼,鼓励练习

这样的 PPT 结构清晰,重点突出,能让听众(尤其是初学者)更容易跟上思路,理解这道题的解法和背后的知识点~

九、最后:编程路上的小鼓励

编程学习就像小鱼的数字游戏,看似简单的问题里藏着扎实的基础。每一道题都是一次积累,每一次调试都是一次成长。不要怕犯错,多动手写代码,多思考为什么,你会发现编程越来越有趣~ 下次遇到类似的问题,相信你一定能轻松解决!加油呀!

http://www.dtcms.com/a/302918.html

相关文章:

  • 【Open3D】入门处理与实战之可视化及相关基本操作
  • 负载均衡算法中的加权随机算法
  • 数论1.01
  • DAY-13 数组与指针
  • Linux应用程序的安装与管理
  • React入门
  • Docker笔记(基本命令、挂载本地gpu、Dockerfile文件配置、数据挂载、docker换源)
  • claude code
  • OSPF路由协议(上)
  • LangGraph实战:MCP + SSE实现远程调用MCP Server
  • 扩展和插件功能
  • 解决Echarts设置宽度为100%发现宽度变为100px的问题
  • 5 分钟上手 Firecrawl
  • [免费]【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts)【论文+源码+SQL脚本】
  • Android中PID与UID的区别和联系(2)
  • Effective C++ 条款07:为多态基类声明virtual析构函数
  • 《深入理解priority_queue:的使用与模拟实现》
  • 教资科三【信息技术】— 学科知识: 第四章(计算机网络技术)
  • 如何在FastAPI中玩转Schema版本管理和灰度发布?
  • 【深度学习】SOFT Top-k:用最优传输解锁可微的 Top-k 操作
  • (二)Eshop(RabbitMQ手动)
  • 如何 5 分钟给英语视频加上中文字幕?
  • 2025.7.28总结
  • 学术论文写作心得笔记:如何避免“论文像实验报告”
  • 关于sql面试积累
  • [Linux]线程池
  • 【深度学习新浪潮】基于文字生成3D城市景观的算法有哪些?
  • 前端实现PDF在线预览的8种技术方案对比与实战
  • 软件设计师-知识点记录
  • WAIC 2025深度解析:当“养虎”警示遇上机器人拳击赛