简介:一套面向北京交通大学计算思维课程大一学生的 Citel 编程题参考代码合集,覆盖巅峰日、并发程序、电梯 II、卡牌、语料字典、字串、字符串变换与字符串映射等常见课内题目,适合在完成作业或复习时用作思路对照。代码以 C++ 实现,共 28 个 cpp 文件,压缩包仅 15KB,轻量易用,下载后可直接查看源码,每个题目独立成文件,便于按题查阅,也能逐题理解算法设计与边界处理。目前已有 1273 人学习下载。代码中保留了完整的函数实现与解题步骤,作者特意强调内容仅供参考,建议读者先独立思考,再通过对比代码定位自己的盲点。对于递归、并发模拟、字符串处理、映射与字典等知识点的综合训练,这套资源能提供具体可跑的参考实现,帮助巩固课上概念并提升编程调试能力。适合刚接触算法编程、需要题目思路启发的大一学生。 如果你是大一上学期坐在BJTU机房里、第一次登录Citel页面的新生,看到满屏英文题面、红色报错和“0分”的判题结果,应该很容易和我当年一样懵。计算思维这门课不是传统意义上的“编程课”,更像是一场用Python解决小问题的思维训练,而Citel就是这场训练的主战场——你写的每一段代码都会被平台自动判题,一点一点打磨你对输入输出、循环、字符串这些基础功的掌控力。
这篇文章把我自己从第一次提交得0分,到后面逐渐摸清Citel路数的全过程整理出来。内容不绕弯子,直接说:Citel这台“判题机器”到底怎么工作、哪些坑是大一新生最容易踩的、常见题型的代码套路长什么样、以及期末前怎么用它高效复习。适合正在被这门课折腾的你,直接对着操作。
1. 先搞懂Citel的“脾气”:它和本地IDE根本不是一回事
1.1 你提交的是“一段代码”,不是“一个工程”
很多同学第一次在Citel上做题,下意识就把自己当成在用PyCharm或者VS Code写项目,总想着先创建一个工程、建几个包、把代码组织得漂漂亮亮。等你真正打开Citel的在线编辑器,你会发现界面朴素得吓人——就是一个代码框,旁边是题目描述,底下是“提交”按钮。
Citel要的只是你的核心解题代码,不需要你做任何工程化设计。我记得有一次帮室友看代码,他把自己的Python文件原封不动复制进去,开头还带着一长串导入自定义模块的语句,结果平台直接报错。原因很简单:平台运行你代码时,用的是它预设的测试环境,你本地依赖的那些文件它根本找不到。
所以在Citel上写题,基本就一个原则:写一个能独立运行的脚本,只用标准库,所有逻辑都堆在这个文件里。
1.2 自动判题的本质:输入、输出、比对
Citel判题的逻辑其实特别机械,就三步:
- 平台准备一组测试输入(可能很多组,它叫“测试点”)
- 用这组输入运行你的程序
- 把你程序打印出来的内容和标准答案逐字比对
这意味着两件很重要的事:
第一,你的代码不能有多余的提示语。比如你写print("请输入一个整数:"),本地跑着没问题,但在Citel看来,这行提示语会混到输出里,和标准答案对不上,直接判错。
第二,样例通过不代表所有测试点都能过。平台展示给你的“示例输入输出”通常是最好算的那组数据,真正的测试点藏在后面,专门刁难边界情况。你本地随便测两下就提交,大概率会收到一个刺眼的WA(Wrong Answer,答案错误)。
2. 输入输出格式:大一第一周最容易全军覆没的地方
2.1 读入数据的几个正确动作
Citel的输入本质上是从终端读数据,Python里最常用的就是input()。但很多新手第一步就栽了:input()读进来的是字符串,不是数字。
比如题目要求“读入一个整数n”,你不能直接拿去算:
n = input() # 这是字符串 print(n * 2) # 如果输入5,输出的是55,而不是10正确姿势是转换类型:
n = int(input()) # 转换成整数如果一行里有多个数,比如“读入两个整数a和b”,可以这样:
a, b = map(int, input().split())split()把一行按空格拆成若干个字符串,map(int, ...)把这批字符串批量转成整数。这是打Citel题最高频的操作之一,建议直接背下来用。
如果题目要求连续读入多行,直到文件结束(EOF),常见写法是:
import sys for line in sys.stdin: line = line.strip() if not line: continue # 处理每一行比反复调input()更稳,尤其是测试数据行数不确定的时候。
2.2 输出格式的“洁癖”:空格、换行、小数位
Citel比对输出时,对格式的要求比你想的严格得多。我自己的血泪教训是:输出多个数时,每两个数之间用一个空格分隔,行尾不能有多余空格,每行结束要换行。
新手最容易犯的错是这样:
for x in ans: print(x, end=" ") # 打印完最后一个数,后面也跟了一个空格这在本地看不出问题,但Citel比对的字符串多了一个空格——WA。
更稳的做法是把结果收集到列表里,最后统一输出:
print(" ".join(map(str, ans)))join只会在元素中间插空格,尾部干干净净没有多余字符,完美符合要求。
再说保留小数位。题目让你“保留两位小数”,不要用round(),因为它只做四舍五入,输出格式不受控。正确打开方式是f-string格式化:
print(f"{average:.2f}")这样输出的数字固定两位小数,浮点误差也不会乱串。
3. 本地运行正常、一交就零分:那些隐蔽的语法与边界问题
3.1 缩进、大小写、保留字的坑
Python程序的灵魂是缩进。你在自己电脑上写代码,PyCharm默认会把Tab转成4个空格,但如果你在Citel的网页编辑器里手敲,或者从Word文档、PDF里复制代码,很容易混入奇怪的制表符或者全角空格——代码看起来一模一样,运行就报IndentationError(缩进错误)。
另一个高频坑是用内置函数名当变量名。我见过一个同学写:
sum = 0 for i in range(n): sum += i print(sum)这段代码本身没错,但如果你之后要用sum()去求列表总和,就会得到一个“int object is not callable”的报错。这种隐蔽问题在综合题里特别容易爆。
还有大小写:Python的True、False、None都是首字母大写,写成true直接报NameError。
3.2 边界值:题目从不按你想象出牌
测试点专门覆盖各种极端情况,比如:
- 输入是0
- 列表只有一个元素
- 字符串是空串
- n取到题目允许的最大值
举个例子,题目要求计算1到n累加和。你写的循环是:
for i in range(1, n): total += i这道题如果n=5,由于range(1, 5)只生成1、2、3、4,结果少了5。这就是经典的“差一错误”。
再看一个我辅导时遇到过很多次的场景:你需要统计一组数中的负数个数,程序里给count变量初始化为0,但如果特殊输入导致循环一次都不进,count的输出就依赖变量是否在函数外定义——很多时候因为漏了初始化,直接报UnboundLocalError。
我的习惯是:所有要累加、要统计的变量,在循环之前必须主动初始化,不要抱着“反正循环里会碰到”的心态。
3.3 死循环和超时:不是报错,但更绝望
Citel的判题有运行时间限制,通常是1秒到几秒不等。如果你的程序陷入死循环,平台会返回Time Limit Exceeded(超时)。
最常见的死循环写法:
while n >= 0: # 忘记在循环体里修改n还有一类是“貌似能跑但很慢”的代码。比如数据规模是10万,你却写了双层循环嵌套,复杂度到了O(n^2),本地测小数据没事,一提交就超时。这时候要找规律简化逻辑,比如用一次循环加字典代替双重循环。
4. 常见题型的模板化写法和易错点
4.1 数值计算类:公式题也要注意精度和类型
数值计算题是计算思维课的“开胃菜”,像温度转换、利润计算、圆的面积这类。公式都给你了,关键是代码别写错。
比如华氏温度转摄氏温度:C = (F - 32) * 5 / 9
f = float(input()) c = (f - 32) * 5 / 9 print(f"{c:.2f}")注意两点:第一,输入用float()接收,用int()会丢精度;第二,除法结果默认是浮点数,直接格式化输出就好,没必要手动转换。
4.2 字符串处理类:反转、去重、凯撒密码
字符串题在Citel题库里占比非常高,因为写法灵活、坑多。
字符串反转是优先级最高的送分题:
s = input() print(s[::-1])切片切片再切片,[::-1]就是倒序,比用循环拼接快得多,也不会漏字符。
凯撒密码这类移位题,本质是ASCII码的偏移:
for ch in s: if 'a' <= ch <= 'z': print(chr((ord(ch) - ord('a') + k) % 26 + ord('a')), end="")很多人第一次写会把% 26放在错误的位置,导致z移位后变成奇奇怪怪的符号。记住:先计算相对偏移(ord(ch) - ord('a') + k),再取模,最后加回ord('a')。
字符去重题有个隐藏陷阱:如果用set(s),结果是乱序的,但题目往往要求保持原顺序。正确做法是:
seen = set() result = [] for ch in s: if ch not in seen: seen.add(ch) result.append(ch) print("".join(result))4.3 逻辑判断与数论模拟:闰年、水仙花数、最大公约数
闰年判断,注意题目完整条件是:能被4整除但不能被100整除,或者能被400整除。很多同学只写了前半句:
if year % 4 == 0: print("Yes")这样1900年这种世纪年就会判错。完整版:
if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0: print("Yes") else: print("No")水仙花数,核心是取各个数位:
a = n // 100 # 百位 b = n // 10 % 10 # 十位 c = n % 10 # 个位 if a**3 + b**3 + c**3 == n: print("Yes")注意运算符优先级,n // 10 % 10从前往后算,先整除再取模,正好得到十位。
最大公约数,直接背辗转相除法:
a, b = map(int, input().split()) while b: a, b = b, a % b print(a)5. 从零分到满分的排查链路:看懂判题反馈比多写十行代码更管用
5.1 先认识Citel的几种判题结果
Citel的反馈其实就是常见的在线判题结果,我总结成一张表:
| 英文状态 | 含义 | 大概率原因 |
|---|---|---|
| Accepted | 通过 | 无 |
| Wrong Answer | 答案错误 | 逻辑有漏洞,或格式多空格、少换行 |
| Presentation Error | 格式错误 | 输出的空白字符与标准答案不一致 |
| Runtime Error | 运行时报错 | 数组越界、除零、变量未定义 |
| Time Limit Exceeded | 超时 | 死循环或算法复杂度过高 |
WA和PE的区别很微妙:答案本身对,只是多了个空格,可能被报成PE;答案错了一部分,通常报WA。很多平台把PE也归到WA里,所以你看到WA先检查格式,再看逻辑。
5.2 用一张“边界用例表”自测
每次提交前,别急着点按钮,先在本地把这些测试数据都跑一遍:
- 最小输入:比如n=0、n=1、空字符串
- 最大输入:取题目允许的极值,验证会不会超时
- 特殊输入:负数、小数、全部相同的字符
- 样例输入:确保示例能过
如果这几类都没问题,再提交。这能帮你剔除掉八成以上的低级错误。
5.3 本地调试的“重定向大法”
很多同学不知道Citel题目给的输入样例是可以直接拿来当文件用的。我的做法是:把样例输入存成一个test.txt,然后在本地终端运行:
python 你的代码.py < test.txt这样命令行终端会直接用文件内容作为键盘输入,效果和Citel判题几乎一样。跑出来的输出再和题目给的“样例输出”逐字对照,比肉眼盯着终端敲数据高效得多。
6. 期末复习阶段:Citel不该只当题库用
6.1 把做过的题按考点重新归类
到期末你会发现Citel里已经躺着几十道题,但它们在你账号里是按时间排列的,没有分类,根本没法复习。
我自己会建一个本地表格,列四列:题目名称、考点标签、当时的错误类型、现在的掌握程度。考完一章节就更新一次。这样做有两个好处:第一,能直观看到自己错得最多的是字符串处理还是循环边界,复习就有方向;第二,考前不用去翻聊天记录找题号,直接按考点刷。
6.2 从“看得懂”到“敲得出来”,中间差了无数次重写
期末前最忌讳的事就是只看参考答案。那道题你觉得自己会了,但把代码挡住,让你现场写,写不出来就是不会。
我期末复习的方法很朴素:每天限时30分钟,在Citel上随机挑三道以前做错的题,要求自己不看任何笔记,直接写,写完就交。第一次肯定会卡壳,但连续一个礼拜之后,键盘上敲input()、split()、join()这些函数就形成肌肉记忆了。
还有一个小心机:把题目里的“测试点覆盖逻辑”当成知识点复习。比如某道题错在没考虑n=0的情况,那就把“这道题为什么会设计0这个测试点”想明白。测试点不是故意刁难你,而是在提醒你,一个健壮的程序必须覆盖所有可能的输入区间。
最后再分享一个小习惯
我在Citel上折腾了一整个学期,最大的感受是:这门课的难点从来不是“算法有多难”,而是“你以为你写对了,但平台不承认”。每次收到WA,别急着改一行再交,先停下来问自己:我的输出是不是多了空格?我的边界条件是不是漏了?我的循环到底能不能停下来?
有段时间我特别沮丧,后来发现一个很有用的方法:提交之前,把代码里的变量名念一遍,大声说清楚“这个变量存的是什么、循环在什么条件下退出”。说话的过程会逼大脑检查逻辑漏洞,很多自己看半天发现不了的bug,一开口就暴露了。
这门课筛选的不是“天生会编程的人”,而是“愿意把细节较真到底的人”。Citel的每一分钟都是这样的训练,撑过去了,后面写任何代码都不虚。
本文还有配套的精品资源,点击获取