NOI C++ 课程体系 / 算法篇 / 第1讲
CSP-J 入门级 · 算法篇 · m4-01

算法概念 与描述

从泡面步骤到计算机程序 —— 理解算法的本质,掌握自然语言、流程图、伪代码三种描述方式,入门枚举法与模拟法。

6 大模块 5 大算法特征 3 种描述方式 2 个入门算法 12 道分层练习
本讲 · 第 25/56 讲算法概念与描述
模块 01

情景导航

用生活中的例子,直觉地理解什么是"算法"。

故事泡面里的算法

小明饿了,决定泡一碗方便面。他在脑子里过了一遍步骤:

第1步:烧开水(3分钟)

第2步:撕开泡面包装,放入碗中

第3步:倒入开水,盖上盖子

第4步:等待 3 分钟

第5步:打开盖子,搅拌均匀,开吃!🍜

这5个步骤,就是一个"算法"!

算法不是高深莫测的东西 —— 任何解决问题的明确步骤,都是算法。泡面有泡面的算法,做菜有做菜的算法,编程也有编程的算法。

💡 从泡面到程序

计算机就像一个超级听话的机器人,你给它一组明确的指令(算法),它就能又快又准地执行。但机器人很"笨"——如果指令不够明确,它就会出错。

所以,好的算法必须满足:步骤清晰、没有歧义、一定能完成。

学算法 = 学习"如何把问题拆成计算机能执行的步骤"

①生活类比:算法无处不在
🍳

菜谱 = 算法

按步骤做菜:先放油→放蒜→放菜→调味→出锅。

→ 顺序执行的算法
🗺️

导航 = 算法

从A到B的最短路径:直走→左转→右转→到达。

→ 图搜索算法
📚

字典查找 = 算法

翻到中间→看大了还是小了→再翻一半→找到!

→ 二分查找算法
🃏

扑克牌排序 = 算法

从手里找出最小的→放最左→再找下一个→排好。

→ 选择排序算法
②编程定义:什么是算法?

算法(Algorithm):为解决某一特定问题而设计的有限的、明确的操作步骤序列。它接受一些输入(也可能没有),经过一系列计算和处理,产生输出。

简单来说:算法 = 输入 + 处理步骤 + 输出

📌 本讲核心知识地图

板块核心内容对应大纲
算法概念定义、五大特征(有穷/确定/可行/输入/输出)算法概念
自然语言描述用中文/英文文字描述算法步骤算法描述:自然语言
流程图描述用标准图形符号表示算法流程算法描述:流程图
伪代码描述介于自然语言和编程语言之间的描述算法描述:伪代码
枚举法逐一列举所有可能,逐个检验入门算法:枚举法
模拟法用程序模拟实际过程入门算法:模拟法
③核心口诀
🔑 算法五大特征

有穷:步骤有限必终止,不能死循环;
确定:每步明确无歧义,机器能执行;
可行:每步能做可实现,不是空想;
输入:零个或多个输入量;
输出:至少一个输出结果!

🔑 三种描述方式

自然语言说人话,好懂但不精确;
流程图画图形,直观但画起来麻烦;
伪代码半代码,精确又好写 —— 竞赛首选!

模块 02

知识探究

深入理解算法的特征,掌握三种描述方式,学习枚举法和模拟法。

1算法的五大特征 必考

一个合格的算法,必须同时满足以下五个特征(由计算机科学家 Knuth 提出):

⏱️
有穷性

算法必须在有限步骤后终止,不能无限循环。

🎯
确定性

每一步操作都必须明确无歧义,不能有"大概""也许"。

✅
可行性

每一步都必须是可以执行的,能在有限时间内完成。

📥
输入

有零个或多个输入。可以没有输入(如输出固定值)。

📤
输出

有一个或多个输出。没有输出的"算法"毫无意义。

特征含义违反的例子正确的例子
有穷性有限步骤内结束❌ "不断加1直到等于∞"✅ "从1加到100"
确定性每步无歧义❌ "加一个合适的数"✅ "加5"
可行性每步可执行❌ "算出π的最后一位"✅ "计算π的前100位"
输入0个或多个—✅ "读入一个整数n"
输出至少1个❌ 只计算不输出✅ "输出结果sum"

💡 Knuth 与《计算机程序设计艺术》

唐纳德·克努特(Donald Knuth)是算法领域的奠基人之一,他在巨著《计算机程序设计艺术》中系统定义了算法的五大特征。他发明的 TeX 排版系统至今仍是学术论文排版的标准工具。

2算法描述方式 ①:自然语言

自然语言描述:用中文或英文的文字来描述算法的步骤。优点是好懂,缺点是可能不够精确,容易产生歧义。

📖 案例:求 1+2+3+…+100 的和

自然语言描述:

第1步:设置一个变量 sum = 0,用来存储累加结果。

第2步:设置一个变量 i = 1,作为当前要加的数。

第3步:如果 i 大于 100,跳到第6步。

第4步:把 i 加到 sum 中(sum = sum + i)。

第5步:i 增加 1(i = i + 1),回到第3步。

第6步:输出 sum 的值,算法结束。

✅ 优点
  • 通俗易懂,非程序员也能看懂
  • 适合描述简单算法
  • 不需要学习特殊符号
❌ 缺点
  • 可能有歧义("加一个数"加多少?)
  • 描述复杂逻辑时冗长混乱
  • 不方便转化为程序代码
3算法描述方式 ②:流程图

流程图(Flowchart):用标准的图形符号来表示算法的逻辑流程。直观清晰,是初赛必考内容。

📐 流程图标准符号

符号形状名称用途
圆角矩形/椭圆起止框表示开始或结束
矩形处理框表示计算、赋值等操作
菱形判断框表示条件判断(是/否)
平行四边形输入/输出框表示数据的读入或输出
带箭头线段流程线表示执行方向和顺序

📊 案例:求 1+2+…+100 流程图

求 1+2+3+…+100 的和
开始 sum=0, i=1 i ≤ 100 ? 否 是 sum = sum + i i = i + 1 输出 sum 结束
✅ 优点
  • 直观,一眼看清逻辑走向
  • 循环、分支一目了然
  • 初赛必考!必须会读会画
❌ 缺点
  • 画起来费时费力
  • 复杂算法画出来很乱
  • 不方便直接转化为代码
4算法描述方式 ③:伪代码

伪代码(Pseudocode):介于自然语言和编程语言之间的一种描述方式。它使用类似编程语言的结构(if/for/while),但不拘泥于语法细节。竞赛中最常用的描述方式。

📝 案例:求 1+2+…+100 伪代码

1// 算法:求 1 到 100 的累加和
2输入:无
3输出:sum(累加和)
4
5令 sum ← 0
6令 i ← 1
7当 i ≤ 100 时,重复执行:
8sum ← sum + i
9i ← i + 1
10输出 sum

🔄 同一算法的 C++ 代码对照

C++sum100.cpp
#include <iostream>
using namespace std;

int main() {
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum = sum + i;
    }
    cout << sum << endl;
    return 0;
}
运行结果
5050
描述方式优点缺点适用场景
自然语言通俗易懂不精确,有歧义给非程序员讲解
流程图直观形象画起来麻烦初赛考试必考
伪代码精确且简洁需要一定编程基础竞赛、论文、教材
5入门算法 ①:枚举法 基础

枚举法(穷举法):把问题所有可能的解逐一列举出来,然后逐个检验是否满足条件。虽然"笨",但简单可靠,是很多复杂算法的基础。

🔑 枚举法三步走

① 确定范围:解在什么范围内?(如 1~100)
② 逐一列举:用循环遍历所有可能
③ 逐个检验:用 if 判断是否满足条件

📖 案例:找出 1~100 中所有能被 7 整除的数

1// 枚举法:找 1~100 中能被 7 整除的数
2对于 i 从 1 到 100,执行:
3如果 i 能被 7 整除(i % 7 == 0):
4输出 i
C++enumerate.cpp
#include <iostream>
using namespace std;

int main() {
    for (int i = 1; i <= 100; i++) {
        if (i % 7 == 0) {    // 检验条件
            cout << i << " ";
        }
    }
    cout << endl;
    return 0;
}
运行结果
7 14 21 28 35 42 49 56 63 70 77 84 91 98

💡 枚举法的经典应用

百钱买百鸡:公鸡5元/只,母鸡3元/只,小鸡1元/3只。用100元买100只鸡,有几种买法?

→ 枚举公鸡数量(0~20)、母鸡数量(0~33),小鸡=100-公鸡-母鸡,检验总价是否=100。

水仙花数:找出所有三位数 abc,满足 a³+b³+c³ = abc。

→ 枚举 100~999 的每个数,拆分各位,检验条件。

6入门算法 ②:模拟法 基础

模拟法:用程序模拟题目描述的实际过程,一步一步地按照题意执行。不需要特殊算法,只需要把题意"翻译"成代码。

🔑 模拟法要点

① 仔细读题:理解题意是模拟法的关键
② 忠实翻译:题目怎么说,程序就怎么做
③ 注意细节:边界条件、特殊情况不能遗漏

📖 案例:约瑟夫问题(简化版)

n 个人围成一圈,从第 1 个人开始报数,报到 m 的人出列。问最后剩下的是第几个人?

当 n=5, m=2 时,模拟过程如下:

🔄 模拟过程 (n=5, m=2)

轮次当前圈报数出列者
初始[1, 2, 3, 4, 5]——
第1轮[1, 2, 3, 4, 5]1→22 出列
第2轮[1, 3, 4, 5]3→44 出列
第3轮[1, 3, 5, 1]5→11 出列
第4轮[3, 5]3→55 出列
结果[3]—剩下 3 号!
C++josephus.cpp — 模拟法
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n = 5, m = 2;
    vector<int> circle;
    for (int i = 1; i <= n; i++)
        circle.push_back(i);  // 初始化圈

int idx = 0;  // 当前位置
    while (circle.size() > 1) {
        idx = (idx + m - 1) % circle.size();  // 报到第m个
        circle.erase(circle.begin() + idx);      // 出列
    }
    cout << "最后剩下:" << circle[0] << endl;
    return 0;
}
运行结果
最后剩下:3

💡 模拟法的经典题目

• 蛇形矩阵:按蛇形顺序填充 n×n 矩阵

• 扑克牌洗牌:模拟洗牌过程

• 日期计算:给定日期,计算是星期几

• 猜数字游戏:模拟猜数字的过程

竞赛中约 30% 的题目可以用模拟法直接解决!

模块 03

实践应用

通过分析和编程题,巩固算法概念和两种入门算法。

题1算法特征判断

题目:以下描述是否构成一个"算法"?为什么?

"从1开始不断加1,直到加到一个足够大的数为止。"

提示:对照算法的五大特征逐一检查。
查看参考答案

不是算法。

违反了确定性:"足够大"是模糊的、不明确的描述,不同人对"足够大"的理解不同。

同时可能违反有穷性:如果"足够大"没有明确上界,可能永远不会终止。

修正:"从1开始加1,加到1000为止" — 这就满足确定性和有穷性了。

题2流程图分析

题目:下面的流程图执行后,输出的结果是什么?

流程:开始 → a=1, b=1 → 判断 a≤5? → 是:b=b×a, a=a+1 → 回到判断
→ 否:输出 b → 结束

查看参考答案

答案:120(即 5! = 5的阶乘)

模拟执行过程:

a=1: b = 1×1 = 1, a = 2

a=2: b = 1×2 = 2, a = 3

a=3: b = 2×3 = 6, a = 4

a=4: b = 6×4 = 24, a = 5

a=5: b = 24×5 = 120, a = 6

a=6 > 5,退出循环,输出 b = 120

这个流程图计算的是 n!(阶乘)!

题3枚举法实战

题目:用枚举法找出 100~999 之间所有的水仙花数(即各位数字的立方和等于该数本身,如 153 = 1³+5³+3³)。

请写出伪代码,并用 C++ 实现。

查看参考答案

伪代码:

1对于 n 从 100 到 999,执行:
2a ← n / 100 // 百位
3b ← (n / 10) % 10 // 十位
4c ← n % 10 // 个位
5如果 a³ + b³ + c³ == n:
6输出 n
C++narcissistic.cpp
#include <iostream>
using namespace std;

int main() {
    for (int n = 100; n <= 999; n++) {
        int a = n / 100;         // 百位
        int b = (n / 10) % 10;  // 十位
        int c = n % 10;         // 个位
        if (a*a*a + b*b*b + c*c*c == n) {
            cout << n << " ";
        }
    }
    cout << endl;
    return 0;
}
运行结果
153 370 371 407

水仙花数共有 4 个:153, 370, 371, 407。

模块 04

总结提升

1核心要点总结
知识板块必须记住的核心
算法定义解决问题的有限的、明确的操作步骤序列
五大特征有穷性、确定性、可行性、输入(≥0)、输出(≥1)
自然语言描述用文字描述步骤,通俗但可能不精确
流程图描述椭圆=起止,矩形=处理,菱形=判断,平行四边形=输入输出
伪代码描述介于自然语言和代码之间,竞赛首选
枚举法逐一列举所有可能 → 逐个检验条件
模拟法忠实模拟题目描述的实际过程
2拓展:算法效率初探

💡 同一个问题,不同算法的效率天差地别

问题:计算 1+2+3+…+n 的和

算法A(枚举累加):循环 n 次,逐一累加。时间 = O(n)

算法B(数学公式):直接用公式 sum = n×(n+1)/2。时间 = O(1)

当 n = 10⁹ 时:算法A需要 10亿次运算(约1秒),算法B只需要 1次运算(瞬间完成)!

结论:好的算法不仅"正确",还要"高效"!这是后续课程的重点。

3思考与启发

💡 学完本讲,你应该明白的5个道理

1. 算法就是解决问题的步骤,它必须有限、确定、可行。

2. 同一个算法可以用自然语言、流程图、伪代码三种方式描述。

3. 流程图是初赛必考内容,必须能读懂和绘制。

4. 枚举法是最朴素但最可靠的算法 —— "暴力出奇迹"。

5. 模拟法考的是读题能力和细节把控 —— "题目怎么说,程序就怎么做"。

模块 05

学习检测

5 个初赛高频易错点。

易错1

程序 = 算法

❌ 错误
"程序就是算法,两者完全一样。"
✅ 正确
程序 = 算法 + 数据结构(Niklaus Wirth 公式)。算法是思路,程序是用某种语言实现的具体代码。
口诀:算法是灵魂,数据是躯体,程序 = 两者合体!
易错2

算法必须有输入

❌ 错误
"算法必须有输入,否则无法运行。"
✅ 正确
算法可以有零个输入。例如"输出1到100的和"不需要任何输入。但输出至少要有1个。
口诀:输入可以为零,输出至少一个!
易错3

流程图菱形框表示处理

❌ 错误
"菱形框用来表示计算操作。"
✅ 正确
菱形 = 判断框(条件分支),矩形 = 处理框(计算操作)。混淆会丢分!
口诀:菱形判断 Yes/No,矩形处理算数值!
易错4

枚举法太慢没有用

❌ 错误
"枚举法太笨了,竞赛中用不上。"
✅ 正确
枚举法是最可靠的方法。竞赛中 30%+ 的题目可以用枚举法拿部分分甚至满分!"暴力出奇迹"。
口诀:不会做的题先枚举,能骗几分是几分!
易错5

模拟法不需要算法

❌ 错误
"模拟法就是把题目抄一遍,不算算法。"
✅ 正确
模拟法也需要仔细分析题意,处理好边界条件和特殊情况。很多模拟题的难点在于细节。
口诀:模拟考细节,一个边界值可能决定 AC 还是 WA!
速查算法概念与描述速查表
知识点关键结论
算法定义有限、明确的解题步骤序列
五大特征有穷、确定、可行、输入(≥0)、输出(≥1)
Wirth 公式程序 = 算法 + 数据结构
自然语言好懂但不精确
流程图椭圆起止 / 矩形处理 / 菱形判断 / 平行四边形IO
伪代码半代码半文字,精确简洁,竞赛首选
枚举法列举所有可能 → 逐一检验条件
模拟法忠实模拟题目描述的实际过程
📌知识点笔记卡

⭐ 算法五特征

有穷、确定、可行

输入(0+)、输出(1+)

缺一不可

📊 流程图符号

椭圆 = 开始/结束

矩形 = 处理

菱形 = 判断

📝 伪代码

介于文字和代码之间

用 if/for/while 结构

不拘泥语法细节

🔍 枚举法

确定范围

逐一列举

逐个检验

🎮 模拟法

仔细读题

忠实翻译

注意边界

⚡ 效率差异

同一问题

不同算法

效率天差地别

课后练习

分层练习作业

A基础 / B提高 / C挑战,难度递增,点击展开答案与解析。

🟢 A组 · 基础(4题)

A1选择题

以下不属于算法特征的是()

A. 有穷性   B. 确定性   C. 高效性   D. 可行性

查看参考答案

答案:C. 高效性

算法的五大特征是:有穷性、确定性、可行性、输入、输出。高效性不是算法的必要特征——一个算法可以很慢,但只要能在有限时间内完成,它仍然是一个合法的算法。

考点:算法的五大特征是有穷性、确定性、可行性、输入、输出,判断时逐条对照即可。

易错:把“高效性/最优性”当成算法的必要条件,其实一个很慢的算法只要有限步内结束,仍然是合法算法。

A2选择题

在流程图中,菱形框表示()

A. 开始/结束   B. 处理操作   C. 条件判断   D. 输入/输出

查看参考答案

答案:C. 条件判断

菱形 = 判断框(是/否分支),矩形 = 处理框,椭圆 = 起止框,平行四边形 = 输入/输出框。

考点:流程图的标准图元:菱形=判断框,矩形=处理框,椭圆=起止框,平行四边形=输入/输出框。

易错:把菱形和平行四边形的含义弄反——(菱形只管“是/否”分支,不负责读写数据)。

A3选择题

"找出1到1000中所有偶数"最适合用哪种算法?

A. 递归法   B. 枚举法   C. 二分法   D. 动态规划

查看参考答案

答案:B. 枚举法

逐一检查 1~1000 中的每个数,判断是否为偶数(i%2==0),这是典型的枚举法。

考点:枚举法的适用场景是“范围有限、可以逐个检查并逐一判断条件”。

易错:看到“找出所有……”就条件反射选二分或贪心,而本题的数据没有任何单调性,只能逐个枚举。

A4选择题

下列关于算法的说法,正确的是()

A. 算法可以没有输出
B. 一个问题的算法是唯一的
C. 算法可以用多种语言描述
D. 算法的步骤可以是无限的

查看参考答案

答案:C

A错(至少1个输出),B错(同一问题可以有多种算法),D错(必须有穷)。C正确:算法可以用自然语言、流程图、伪代码等多种方式描述。

考点:算法描述方式(自然语言、流程图、伪代码)与“有穷、确定、有输入、有输出”四条约束的综合判断。

易错:误认为“算法必须有输入”或“同一个问题只有唯一算法”,这两句话都不成立。

🟡 B组 · 提高(4题)

B1流程图分析

以下流程图执行后输出的值是多少?

开始 → x=1, s=0 → 判断 x≤10? → 是:若x为偶数则 s=s+x,x=x+1 → 回到判断
→ 否:输出 s → 结束

查看参考答案

答案:30

模拟执行:x从1到10,只有偶数时才累加:

s = 2 + 4 + 6 + 8 + 10 = 30

这个算法求的是 1~10 中所有偶数的和。

思路:按循环变量 x 从 1 走到 10 逐步跟踪,只在判断框“x 是偶数”成立时执行累加。

易错:把判断条件看成“x 是奇数”,或漏掉最后一次 x=10 的累加,算出 25 之类的错误值。

B2枚举法

用枚举法解决"百钱买百鸡"问题:公鸡5元/只,母鸡3元/只,小鸡1元/3只。用100元买100只鸡(每种至少1只),有多少种买法?

查看参考答案
C++chickens.cpp
#include <iostream>
using namespace std;

int main() {
    int count = 0;
    for (int g = 1; g <= 20; g++) {       // 公鸡最多20只
        for (int m = 1; m <= 33; m++) {   // 母鸡最多33只
            int x = 100 - g - m;          // 小鸡数量
            if (x >= 1 && x % 3 == 0) {  // 小鸡至少1只且能被3整除
                if (5*g + 3*m + x/3 == 100) {
                    count++;
                    cout << "公鸡" << g << " 母鸡" << m << " 小鸡" << x << endl;
                }
            }
        }
    }
    cout << "共" << count << "种买法" << endl;
    return 0;
}
运行结果
公鸡4 母鸡18 小鸡78
公鸡8 母鸡11 小鸡81
公鸡12 母鸡4 小鸡84
共3种买法

思路:用等量关系 g+m+x=100 把三重循环降为双重循环,小鸡数 x 直接由表达式算出后再校验合法性。

易错:只判断 x≥1 却忘了 x%3==0(小鸡按“1 元 3 只”,只数必须能被 3 整除),或漏掉“每种至少 1 只”的限制。

B3伪代码

请用伪代码描述"判断一个正整数 n 是否为素数"的算法。

查看参考答案
C++完整参考代码
#include <iostream>
#include <cmath>
using namespace std;

// 伪代码:判断正整数 n 是否为素数
// 输入:正整数 n
// 输出:是 / 否
bool isPrime(int n) {
    if (n < 2) return false;              // n < 2,输出“不是素数”,结束
    for (int i = 2; i <= sqrt(n); i++) {  // 对于 i 从 2 到 √n,执行
        if (n % i == 0) return false;     // 若 n % i == 0,输出“不是素数”,结束
    }
    return true;                          // 一个因子都没找到 -> 是素数
}

int main() {
    int n;
    cin >> n;
    if (isPrime(n)) cout << "是素数" << endl;
    else            cout << "不是素数" << endl;
    return 0;
}

答案:伪代码如下(n 为正整数):
输入:正整数 n  输出:是 / 否
如果 n < 2,输出“不是素数”,结束
对于 i 从 2 到 √n,执行:
    如果 n % i == 0:
        输出“不是素数”,结束
输出“是素数”

思路:素数是只能被 1 和自己整除、且大于 1 的数。判断时从 2 开始一个个试除,只要有一个 i 能整除 n,n 就不是素数;如果一路试到 √n 都没找到因数,就说明 n 是素数。关键优化是只需检查到 √n:因为如果 n 有一个大于 √n 的因数,那它必然还配着一个小于 √n 的因数,早就被我们发现了。

考点:伪代码的书写规范(输入/输出、判断、循环、提前结束);素数判定算法;√n 优化把复杂度从 O(n) 降到 O(√n)。

易错:① 忘记特判 n < 2,导致 1 被判成素数;② 循环上界写成 i < n(没优化)或 i < √n(漏掉完全平方数,如 9=3×3),应写 i <= sqrt(n) 或 i*i <= n;③ 用 sqrt 时要留心浮点误差,写 i*i <= n 更稳。

B4模拟法

一个骰子初始时顶面为1,按"前、右、前、右"的顺序翻转4次(每次90度),最终顶面是多少?(假设标准骰子:1对6,2对5,3对4)

查看参考答案

模拟过程:

初始:顶=1, 底=6, 前=2, 后=5, 左=3, 右=4

第1次(向前翻):顶=5, 底=2, 前=1, 后=6, 左=3, 右=4

第2次(向右翻):顶=3, 底=4, 前=1, 后=6, 左=2, 右=5

第3次(向前翻):顶=6, 底=1, 前=3, 后=4, 左=2, 右=5

第4次(向右翻):顶=2, 底=5, 前=3, 后=4, 左=1, 右=6

最终顶面 = 2

思路:把骰子的顶/底/前/后/左/右六个面写成变量,每翻一次按规则整体更新这组变量再继续下一步。

易错:翻动时只改“顶面”而忘了同步更新底面和四个侧面,后面的步骤会全部算错。

🔴 C组 · 挑战(4题)

C1初赛真题

下列关于算法的说法中,正确的有()个。

① 算法必须在有限步骤内结束
② 算法的每一步骤必须是确定的
③ 算法可以没有输入
④ 算法可以没有输出
⑤ 算法必须有至少一个输出

A. 2   B. 3   C. 4   D. 5

查看参考答案

答案:C(4个)

① ✅ 有穷性   ② ✅ 确定性   ③ ✅ 可以没有输入

④ ❌ 算法必须至少有一个输出   ⑤ ✅ 正确

④ 和 ⑤ 是矛盾的,⑤ 正确则 ④ 错误。共 4 个正确。

考点:逐条比对算法五大特征,注意“输入可以为 0 个”,而“输出至少要有 1 个”。

易错:凭印象直接数条数,遇到两条表述互相矛盾时又以错的那条为准——应以课本定义为唯一标准。

C2初赛真题

以下流程图表示的算法,当输入 n=6 时,输出结果是()

开始 → 输入 n → s=0, i=1 → 判断 i≤n? → 是:s=s+i*i, i=i+1 → 回到判断
→ 否:输出 s → 结束

A. 21   B. 91   C. 36   D. 55

查看参考答案

答案:B. 91

该算法计算 1²+2²+3²+4²+5²+6²

= 1 + 4 + 9 + 16 + 25 + 36 = 91

思路:循环累加的项是 i²,i 从 1 走到 n,把 n=6 代入逐项求出平方和。

易错:把 i² 当成 i 本身累加(得到 21),或漏加最后一项 36。

C3枚举法实战

用枚举法编程:找出所有三位数中,满足"各位数字之和等于各位数字之积"的数。

查看参考答案
C++sum_eq_product.cpp
#include <iostream>
using namespace std;

int main() {
    for (int n = 100; n <= 999; n++) {
        int a = n / 100;
        int b = (n / 10) % 10;
        int c = n % 10;
        if (a + b + c == a * b * c) {
            cout << n << " ";
        }
    }
    cout << endl;
    return 0;
}
运行结果
123 132 213 231 312 321

满足条件的数都是 1、2、3 的排列,因为 1+2+3 = 6 = 1×2×3。

思路:枚举 100~999,用 n/100、(n/10)%10、n%10 拆出百十个位,再比较数位和与数位积是否相等。

易错:拆位时整除与取余混用(如写成 n%100/10 之外的错误组合),取到的不是对应位的数字。

C4综合应用

用模拟法编程:模拟一个简单计算器,支持加减乘除。输入一个表达式(如 3 + 5 * 2 - 1,不含括号,按从左到右顺序计算),输出结果。

查看参考答案
C++calculator.cpp
#include <iostream>
using namespace std;

int main() {
    int result;
    cin >> result;  // 读入第一个数

char op;
    while (cin >> op) {
        int num;
        cin >> num;
        if (op == '+') result += num;
        else if (op == '-') result -= num;
        else if (op == '*') result *= num;
        else if (op == '/') result /= num;
    }
    cout << result << endl;
    return 0;
}
运行结果
输入: 3 + 5 * 2 - 1
输出: 15
(从左到右:(3+5)=8, 8*2=16, 16-1=15)

注意:这是从左到右计算(不考虑运算符优先级),与标准数学运算不同。如果需要考虑优先级,则需要更复杂的算法(如栈或递归下降)。

思路:先读入第一个数作为当前结果,再循环“读运算符→读下一个数→按运算符更新结果”,把表达式从左到右逐段折叠。