作为一名即将踏入算法竞赛征程的选手,需要对算法竞赛具备基础的认知。本章就带你了解算法竞赛的类型,选择趁手的编程语言,并使用便捷的编程工具,完成第一个程序。

0.1 关于算法竞赛

算法竞赛主要考查选手运用算法、数据结构和数学知识,通过编写程序解决实际问题的能力。参加算法竞赛除了可以提升选手的逻辑思维能力,还可以在未来考大学、参加工作时增加筹码。因此算法竞赛也是许多头部科技公司招聘用人的重要参考指标之一。

算法竞赛的形式多种多样,有线上赛、线下赛、周赛、月赛等,不同比赛的赛制规则也不尽相同。涵盖的选手年龄跨度也很大,从小学生到已经工作的成年人,都能找到适合自己的算法竞赛。下面对国内主流的算法竞赛赛制进行简单介绍。

OI 赛制:赛时不能得到实时反馈,每道题都有多个测试点,通过相应的测试点就可以得到对应的分数。如果是线下赛,选手仅有一次提交代码的机会;如果是线上赛,选手可以多次提交,但是仅以最后一次提交的代码作为最终结果。OI 赛制的比赛有 CSP-J/S 第二轮、NOIP、省选、NOI、蓝桥杯(线上赛)、CSP。

IOI 赛制:选手有多次提交代码的机会,赛时实时评测并将结果反馈给选手,每道题都有多个测试点,通过相应的测试点就可以得到对应的分数,最终得分为选手所有提交中的最高得分。IOI 赛制的比赛有 PAT、天梯赛(团队赛)。GESP 的编程题每道题最多只能提交 32 次,实施评测并反馈评测结果,仅以最后一次提交的代码作为最终结果。

除了上述比赛之外,一些用户比较多的在线评测网站(Online Judge,简称 OJ)也有组织线上赛。比如力扣的周赛和双周赛,主要面向工作求职;洛谷月赛,主要面向信竞选手;Codeforces 和 Atcoder 的周赛是国外比较知名的 OJ,面向全球算法爱好者,许多现役与退役选手都会参加 Codeforces 和 Atcoder 的周赛,常年霸榜前十。

0.2 关于编程语言

算法竞赛既然是编写程序解决问题,自然应该选择一门编程语言与计算机进行沟通。编程语言从发展历程上来说大体可以划分为机器语言、汇编语言、高级语言三个阶段。

机器语言是计算机发展早期唯一的程序设计语言,由 01 序列组成,又称二进制语言,是计算机唯一可以直接识别和执行的语言。特定型号的计算机有其专用的机器语言规范,程序不能在不同的硬件上执行,使用机器语言编写程序和调试排错都很困难。

汇编语言是机器语言之后的演化,使用带符号或助记符的指令和地址代替二进制代码,并使用汇编程序将汇编语言代码翻译为机器语言。尽管汇编语言大大提高了编程效率,但仍然需要程序员在所使用的硬件上花费大量精力,使用符号语言编程也很不直观。

高级语言适用于许多不同的计算机,使程序员能够关注要解决的问题,将精力集中在应用程序上,无需考虑计算机的复杂性。高级语言的设计目标是使程序员摆脱汇编语言繁琐的细节。高级语言必须转化为机器语言才能被识别和执行,该过程称为编译或解释,由编译器或解释器实现。高级语言程序称为源程序,被翻译成的机器语言程序称为目标程序。

按照高级语言转换成机器语言的方式可以将程序设计语言分为解释型语言编译型语言两类。

  • 解释型语言:由语言特定的解释程序逐步解释执行,程序每次运行都需要源代码或字节码的参与,例如 Python、PHP、Java 等。
  • 编译型语言:由编译程序将文本形式的源代码翻译成机器语言文件(目标文件),以后每次执行程序时只需要执行目标文件。只要源代码不变,就不必重新编译。例如 C/C++、Pascal 等。

此外,按照程序设计的思想可以将程序设计语言分为面向过程和面向对象两类。面向过程的语言有 C 语言、Pascal、Fortran 等;面向对象的语言有 C++、Java、C#、Python 等。

许多线上的算法竞赛是不限制编程语言的,不过国内的比赛大多会指定编程语言。比如 CSP-J/S 第二轮、NOI 系列赛事均指定 C++ 为参赛语言,蓝桥杯分为 C/C++、Python、Java 等不同组别,GESP 分为 C++、Python 等组别。

几乎所有比赛都支持 C++ 语言,C++ 语言又支持绝大部分 C 语言的语法,因此建议大家在学习过程中使用 C++ 作为语言工具,同时学习一些 C 语言中有利于竞赛编程的特性。

0.3 在线评测系统

合理有效地使用 OJ,通过在 OJ 上刷题检验自己的学习成果,能够让你的算法学习之路事半功倍。目前大多数 OJ 都有国内外知名比赛的往届真题,通过刷这些题目,可以熟悉算法竞赛的命题模式,快速进入算法竞赛的状态。

本书绝大部分例题和习题均选自国内外比赛/考级真题,为了便于大家进行提交测试,这些题目均已上传到 SuperOJ(https://superoj.online),针对 GESP 和电子学会考级设置了单独的题库。题目编号以字母 P 开头的题目在主题库,字母 G 开头的题目为 GESP 考级真题,字母 D 开头的题目为电子学会考级真题。

在 OJ 上提交源程序之后,OJ 会根据题目配置的输入数据来测试你的程序运行结果是否正确,你大致会遇到如下几种评测结果:

  • W a i t i n g \tt Waiting Waiting:正在等待,表明你的程序已经进入评测队列,正在排队等待评测。
  • A c c e p t e d \tt Accepted Accepted:答案正确,表明你的程序运行结果正确无误。
  • W r o n g   A n s w e r \tt Wrong\ Answer Wrong Answer:答案错误,表明你的程序运行过程没问题,但是计算结果错误。
  • C o m p i l e   E r r o r \tt Compile\ Error Compile Error:编译错误,表明你的程序存在语法错误,无法正确编译。
  • R u n t i m e   E r r o r \tt Runtime\ Error Runtime Error:运行时错误,表明你的程序在运行过程中异常终止了,比如被 0 除、数组空间不足、数组下标非法越界等。
  • M e m o r y   E x c e e d \tt Memory\ Exceed Memory Exceed:内存超限,表明你的程序占用的内存空间超出了题目限制。
  • T i m e   E x c e e d \tt Time\ Exceed Time Exceed:时间超限,表明你的程序运行时间超出了题目限制。
  • O u t p u t   E x c e e d \tt Output\ Exceed Output Exceed:输出超限,表明你的程序输出了题目规定之外的信息。

0.4 准备编程工具

工欲善其事,必先利其器,选择趁手的编程工具能让你在编写程序时少一些烦恼。虽然多数 OJ 都配备了在线编辑工具,但是线下赛是用不了在线工具的,因此务必掌握至少一个 IDE(集成开发环境)的安装和使用方法。

所谓 IDE 是一种工具软件,包含程序员编写和测试程序所需的所有基本工具,通常包含源代码编辑器、编译器或解释器以及调试器。目前比较好用的轻量级 C/C++ IDE 有 Dev C++ 和 Code::blocks,这两款编程工具的安装过程都很简单,上手也很容易,对纯新手和中小学生很友好。

有一定编程经验,对计算机比较熟悉的选手可以选择 VS Code,这是一款强大的文本编辑工具,通过安装 C++ 相关插件可以很好的辅助你编写 C++ 程序。不过它需要额外安装编译器,建议使用 g++ 的最新稳定版。

0.5 第一个 C++ 程序

【小贴士】编写 C++ 代码时必须使用英文输入法,包括所有的标点符号。

接下来开始编写第一个 C++ 程序。打开你的代码编辑工具,新建一个源程序文件,将输入法切换到英文模式,并编写如下代码。

#include <iostream>
using namespace std;

int main()
{
    cout << "Talk is cheap. Show me the code.";

    return 0;
}

编写完成之后将其保存到一个你容易找的目录下,然后按下编译运行按钮,会在控制台或终端输出 Talk is cheap. Show me the code. 这句话。你应该已经猜出上面这个程序的功能了,就是在控制台或终端输出一句话。下面我们详细剖析一下这个程序。

#include <iostream> 的作用是将头文件 iostream 中的 “工具” 包含到当前文件中来。具体来说,头文件 iostream 中囊括了 C++ 输入输出所需要的 “工具”,要想让程序进行交互,就需要包含此头文件。在源程序中,任何形如 #include <filename> 的行都将被替换为 f i l e n a m e \tt filename filename 文件的内容。如果找不到对应文件,编译器将显示出错信息。

using namespace std; 的作用是使用标准命名空间。所谓命名空间是 C++ 为了解决多人分工协作时,可能出现的标识符命名冲突问题。而标准命名空间 std 是 C++ 为了保持与 C 语言的兼容性而做出的妥协。将原来 C 语言的函数库复制一份,并在此基础上稍加修改,把变量、函数、类等纳入命名空间 std 下,即标准命名空间。

我们把下面的代码称为主函数,这是一个 C++ 程序中非常重要的部分,任何一个单文件源程序都是从主函数开始执行的,遇到 return 0; 就结束执行,其中的细节暂时不用深究。事实上,下面的代码也是一个完整的 C++ 程序,只不过这个程序并没有输出任何信息。

int main()
{
    return 0;
}

cout << "Talk is cheap. Show me the code."; 这行代码是真正执行输出功能的语句。其中 cout 是执行输出的工具,<< 称为流插入运算符,表明将该运算符后面的内容插入到输出流中。需要注意的是,只有用英文模式的双引号包含的内容才会原样输出,如果直接输出这句话而不加双引号,会导致编译错误。

你可以在SuperOJ上的电子学会题库中找到【D1302 [天梯赛] 嫑废话上代码】这道题,并将刚刚写好的代码提交上去进行评测。

上面的源程序中有 3 行代码末尾出现了分号,分号是 C++ 程序中语句结束的标志。一般而言,我们所写的多数代码末尾都必须添加分号。而且为了保证代码的可读性,每条语句单独占据一行,如下面的例子。

#include <iostream>
using namespace std;

int main()
{
    cout << "How Can We Live a Joyful Life" << endl;
    cout << "Without Programming";

    return 0;
}

编译运行之后会发现在控制台上分两行输出了两句话,然而输出结果的换行并不是因为我们在代码中换了行,而是 endl 起到了换行作用。控制台输出的信息是我们需要计算机去做的事情,只有我们通过 endl 告诉它需要换行,它才会执行换行。代码中分开两行写只是为了增强代码的可读性。

可以发现在 endl 前面也写了一个流插入运算符(<<),这是因为一个流插入运算符只能将一个信息插入到输出流,endl 和前面的那句话是两个不同的信息,因此各自需要一个流插入运算符。此外我们还发现,一个 cout 可以配合多个流插入运算符进行连续输出。

你可以在 SuperOJ 上的电子学会题库中找到【D1337 [24 年 12 月一级] 好之者不如乐之者】这道题,并将刚刚写好的代码提交上去进行评测。

本节习题

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐