一、题目重现
题目描述
小 R 和小 X 买了两张二等座高铁票,车票上写着车厢号和座位号,两人希望座位能挨在一起。
列车共 17 节车厢(01~17),其中 01 和 16 号是一等座车厢,其余是二等座车厢,两人买的都是二等座。每节二等座车厢有 18 排,每排 5 个座位,座位号由「两位排号 + 一位大写字母」组成,例如 03C 表示第 3 排 C 座。
每一排的座位从左到右依次是 A、B、C、D、F,其中 C 座与 D 座之间是过道:
A B C | 过道 | D F
└── 左侧三人 ──┘ └ 右侧两人 ┘
原题附有座位示意图,上面是它的文字还原。两件小事要记牢:字母里没有 E;C 和 D 之间隔着过道,不算相邻。
相邻的定义是:在同一节车厢的同一排、位于过道同一侧,且在该侧的座位序列中紧挨着。
需要依次回答四个问题,输出一个长度为 4 的 01 字符串(1 代表是,0 代表否):
- 两张票是否在同一节车厢;
- 是否在同一节车厢的同一排;
- 是否在同一节车厢的同一排、且位于过道同一侧;
- 两个座位是否相邻。
输入格式
一行四个字符串 c1 s1 c2 s2,依次是小 R 的车厢号、座位号,小 X 的车厢号、座位号。
输出格式
一行一个长度为 4 的 01 字符串。
输入输出样例
| 样例 | 输入 | 输出 | 说明 |
|---|---|---|---|
| 1 | 02 01A 02 01B |
1111 |
同车厢、同排、同侧,A 与 B 紧挨着 |
| 2 | 02 01C 02 01A |
1110 |
同侧,但 C 与 A 中间隔着 B |
| 3 | 02 01C 02 01D |
1100 |
C 在左、D 在右,中间是过道 |
| 4 | 02 02B 02 01A |
1000 |
都是 02 车厢,但不同排 |
| 5 | 02 01A 03 01A |
0000 |
车厢都不同 |
数据范围与约定
- 车厢号是 01~17 中除 01、16 外的两位数字;排号是 01~18 的两位数字;座位字母是 A、B、C、D、F 之一;两张票不是同一个座位;
- 题目保证两张票都在二等座车厢,不需要自行判断一等座;
- 原题时限 1.0 秒,内存 1024 MiB。
二、先把样例玩一遍
把五个样例摆在一起看,一个规律立刻冒出来:一旦某一位是 0,它右边全是 0。
| 输入 | 同车厢 | 同排 | 同侧 | 相邻 | 输出 |
|---|---|---|---|---|---|
02 01A 02 01B |
1 | 1 | 1 | 1 | 1111 |
02 01C 02 01A |
1 | 1 | 1 | 0 | 1110 |
02 01C 02 01D |
1 | 1 | 0 | 0 | 1100 |
02 02B 02 01A |
1 | 0 | 0 | 0 | 1000 |
02 01A 03 01A |
0 | 0 | 0 | 0 | 0000 |
原因藏在题目措辞里:第 2、3、4 问的条件把前面的条件全包进去了。后面成立,前面必然成立;前面不成立,后面一定不成立。像四层套娃,一层倒了,里面全倒。
三、两个让代码变短的秘密
秘密一:不用把 “02” 变成数字 2
车厢号 c1、c2 是字符串(如 "02"),判断相等直接写 c1 == c2 就行,不需要转成整数。同理,座位号 01A 的前两个字符就是排号,s.substr(0, 2) 取出 "01" 也直接比字符串;最后一个字符用 s.back() 取出来。
能偷这个懒,是因为题目保证车厢号和排号都是两位数,位数一样,比字符串和比数字结果相同。
秘密二:两张小查表代替一堆分支
左右表 side©:A、B、C 在左侧记 0,D、F 在右侧记 1。
队内编号表 seat©:在自己那一侧排第几,从 0 开始数。
| 字母 | A | B | C | D | F |
|---|---|---|---|---|---|
| side(哪一侧) | 0 | 0 | 0 | 1 | 1 |
| seat(队内编号) | 0 | 1 | 2 | 0 | 1 |
于是「相邻」就一句话:同一侧,且队内编号刚好差 1。
- A 与 B:同侧,0 与 1 差 1,相邻;
- C 与 A:同侧,2 与 0 差 2,不相邻;
- D 与 F:同侧,0 与 1 差 1,相邻;
- C 与 D:一个左一个右,
side就不同了,不相邻(正好是过道规则)。
四、手算一个样例
以 02 01C 02 01D 为例:
| 步骤 | 算什么 | 结果 |
|---|---|---|
| 1 | "02" == "02" |
1 |
| 2 | 同车厢,且 "01" == "01" |
1 |
| 3 | side('C')=0 与 side('D')=1 |
0 |
| 4 | 上一步已经是 0 | 0 |
拼起来就是 1100。四个判断与题目条件一一对应,前面不成立时后面全部被 && 挡住,不会误判。
五、参考代码(AC)
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int side(char c) {
return (c == 'A' || c == 'B' || c == 'C') ? 0 : 1;
}
int seat(char c) {
if (c == 'A') return 0;
if (c == 'B') return 1;
if (c == 'C') return 2;
if (c == 'D') return 0;
return 1;
}
int main() {
string c1, s1, c2, s2;
if (!(cin >> c1 >> s1 >> c2 >> s2)) return 0;
bool sameCar = c1 == c2;
bool sameRow = sameCar && s1.substr(0, 2) == s2.substr(0, 2);
char a = s1.back(), b = s2.back();
bool sameSide = sameRow && side(a) == side(b);
bool adjacent = sameSide && abs(seat(a) - seat(b)) == 1;
cout << (sameCar ? '1' : '0') << (sameRow ? '1' : '0')
<< (sameSide ? '1' : '0') << (adjacent ? '1' : '0') << '\n';
return 0;
}
六、代码逐段解析
side()里的? :读作「如果…就…否则…」:是 A/B/C 返回 0,否则返回 1。seat()用四个if查表,最后一个return 1剩下的只可能是 F。if (!(cin >> ...)) return 0;是一句安全护栏:输入为空时安静结束,不会乱跑。- 四个
bool用&&连成链条,正是「套娃」:A && B只要 A 不成立,整个就是假的。 abs(seat(a) - seat(b)) == 1用abs求相差多少,不管谁大谁小;<cstdlib>提供它。- 输出用四次
(条件 ? '1' : '0'),把bool直接变成字符,四个字符连着打印再换行。
七、复杂度分析
输入永远只有 4 个短字符串,代码里没有任何循环,只做几次比较:时间 O(1),内存 O(1)。这道题慢不下来,也不会超时。
八、易错点清单
- 别把 C 和 D 当邻居:中间是过道,靠
side()挡住。 - 别以为字母 A~F 连续:没有 E,不能用
'F' - 'A'当编号,必须查表。 - 排号取两位:
substr(0, 2),写成substr(0, 1)会让第 10~18 排全乱。 - 别漏套娃:只写
side(a) == side(b)而不带上sameRow,会输出错位答案。 - 不用检查车厢是不是一等座:题目已保证,多余判断反而容易写错。
- 文件输入输出:原题要求
travel.in/travel.out,上面的代码为了方便阅读改用标准输入输出;在 OJ 提交时请按题目要求加回freopen。
九、考点总结
| 考点 | 本题怎么用 |
|---|---|
| 字符串处理 | substr 取排号、back 取字母、直接比较两位编号 |
| 逻辑链条 | 四个递进条件用 && 串联,天然保证「前面假后面全假」 |
| 查表思想 | 把座位规则压成 side / seat 两张表,避免一长串 if |
一句话记住:四个问题是套娃,座位规则查两张表,相减看差的绝对值是不是 1。
本文题面整理自 CCF CSP-J 2026 第二轮(入门组)试题,题目版权归中国计算机学会所有。题解与代码由椰程信奥整理撰写,参考答案仅供参考,最终以 CCF 官方公布为准。



