B3979 [信息与未来 2024] 红绿灯
题目描述
七段数码管是一种用来显示数字的电子元件,由七个可以发光的小段组成,这些小段排列成一个数字
的形状。通过点亮不同的段,数码管可以显示出从
到
的数字。每个小段都有一个名字,从
到
,按下图方式排列和命名:
数码管通过点亮不同的段显示不同的数字。例如:
数字
需要点亮
段。
数字
需要点亮
段。
数字
需要点亮
段。
Dr. X 发现,红绿灯上的数码管经常发生故障,故障分为两类:常亮和不亮:
如果数码管的某段发生了常亮故障,这一段都会始终保持点亮的状态。
如果数码管的某段发生了不亮故障,这一段都会始终保持不亮的状态。
今天,Dr. X 感觉红绿灯的一个数字显示异常,因此记录了数码管显示数字的日志。Dr. X 希望 你根据日志推测数码管的每一段分别可能发生了怎样的故障?
输入格式
输入数据第一行一个整数
,代表 Dr. X 日志的数量。接下来
行,每行一条日志 (一个字符 串):
日志从一个数字
开始,代表本次观察的数字。
紧跟着数字的是若干的字母(
,且每个字母至多出现一次),代表观察到数字
显示时,处于“亮”状态的数码管段。日志准确、没有遗漏地记录了数码管亮着的段,且记录日志的过程中,红绿灯的状态保持不变:常亮的段一直常亮、不亮的段一直不亮、正常的段一直正常。日志中可能有同一个数字的多次记录,但不会自相矛盾。
输出格式
输出一行
个字符,分别代表数码管
段的状态。对于每一段,如果有证据表明它常亮,输出大写字母X。如果有证据表明它不亮,输出小写字母x,否则输出半角减号-。
输入输出样例 #1
输入 #1
3
1BCD
7BCD
7DCB
输出 #1
x--X---
输入输出样例 #2
输入 #2
3
0
1
8G
输出 #2
xxxxxx-
说明/提示
对于
的数据,满足
。
本题原始满分为
。
题目分析
七段数码管的每个段可能出现两种故障状态:
常亮(X):该段在所有显示中必须亮
不亮(x):该段在所有显示中必须不亮
正常(-):无明确证据
通过日志推断故障状态的逻辑:
日志记录格式:数字k+实际亮起的段
每个数字的正确亮段集合已知(如数字0对应段A,B,C,D,E,F)
矛盾判断规则:
当某段本应亮但实际未亮 该段存在"不亮"故障(x)
当某段本不应亮但实际亮 该段存在"常亮"故障(X)
解题步骤
1. 初始化正确段集合
预定义数字0-9对应的正确亮段集合:
correct = {'A','B','C','D','E','F'};
correct = {'B','C'};
correct = {'A','B','D','E','G'};
correct = {'A','B','C','D','G'};
correct = {'B','C','F','G'};
correct = {'A','C','D','F','G'};
correct = {'A','C','D','E','F','G'};
correct = {'A','B','C'};
correct = {'A','B','C','D','E','F','G'};
correct = {'A','B','C','D','F','G'};
2. 解析输入日志
输入格式:
第一行为日志数量n
后续n行为日志条目,格式为
表示显示的数字(0-9)
表示实际亮起的段(字母 A-G,顺序无关,可能为空)
解析逻辑:
将每条日志拆分为数字k和实际亮段集合
示例:
输入日志 "7DCB" 解析为:
数字 k = 7
实际亮段集合 = {'D', 'C', 'B'}
3. 段状态分析(A-G逐个判断)
分析逻辑
对每个段(A-G)执行以下检查:
不亮故障(x)判断条件
若某段 本应亮起(根据当前显示数字的正确段集合),但 实际未亮 该段存在"不亮"故障
触发条件:s ∈ correct[k]且s ∉ observed_segments
常亮故障(X)判断条件
若某段 本应熄灭(根据当前显示数字的正确段集合),但 实际亮起 该段存在"常亮"故障
触发条件:s ∉ correct[k]且s ∈ observed_segments
终止规则
发现 任一矛盾(x或X条件满足)时,立即停止检查后续日志
示例:若段A在某条日志中触发X条件,后续日志无需再检查段A
4. 输出结果逻辑与实现
核心逻辑
输出结果由7个字符组成,按顺序对应A-G段的故障状态。每个字符的判定遵循以下规则:
X:存在至少一条日志证明该段存在"常亮故障"(不应亮但实际亮):ml-citation{ref="1,2" data="citationList"}
x:存在至少一条日志证明该段存在"不亮故障"(应亮但实际未亮):ml-citation{ref="1,2" data="citationList"}
-:无任何日志可推断故障类型:ml-citation{ref="1,2" data="citationList"}
实现要点
遍历顺序:严格按A-G顺序生成结果字符串
故障优先级:
若同时存在X和x触发条件(理论上不可能,因日志不自相矛盾)
实际实现中,按代码执行顺序优先标记最先发现的故障类型:ml-citation{ref="1" data="citationList"}
参考题解代码:
#include <bits/stdc++.h>
usingnamespacestd;
intmain(){
// 初始化每个数字正常显示时应该点亮的段
vector<set<char>> correct(10);
correct[0] = {'A','B','C','D','E','F'}; // 数字0
correct[1] = {'B','C'}; // 数字1
correct[2] = {'A','B','D','E','G'}; // 数字2
correct[3] = {'A','B','C','D','G'}; // 数字3
correct[4] = {'B','C','F','G'}; // 数字4
correct[5] = {'A','C','D','F','G'}; // 数字5
correct[6] = {'A','C','D','E','F','G'};// 数字6
correct[7] = {'A','B','C'}; // 数字7
correct[8] = {'A','B','C','D','E','F','G'};// 数字8
correct[9] = {'A','B','C','D','F','G'};// 数字9
int n; // 日志数量
cin >> n;
vector<pair<int, set<char>>> logs; // 存储日志
for (int i = 0; i < n; ++i) {
string s; // 读取日志
cin >> s;
int k = s[0] - '0'; // 日志中的数字
set<char> seg; // 日志中亮着的段
for (size_t j = 1; j < s.size(); ++j) seg.insert(s[j]); // 添加亮着的段
logs.emplace_back(k, seg); // 存储日志
}
// 初始化结果字符串,默认状态为不确定(-)
stringres(7, '-');
string segs = "ABCDEFG"; // 段的名称
for (int i = 0; i < 7; ++i) {
char s = segs[i]; // 当前检查的段
bool x = false, y = false; // x表示常亮故障,y表示不亮故障
for (constauto& log : logs) { // 遍历所有日志
int k = log.first; // 日志中的数字
constauto& cs = correct[k]; // 该数字正常显示时应点亮的段
if (cs.count(s)) { // 如果该段在正常显示中应该亮
if (!log.second.count(s)) y = true; // 如果日志中该段没亮,标记为不亮故障
} else { // 如果该段在正常显示中应该不亮
if (log.second.count(s)) x = true; // 如果日志中该段亮了,标记为常亮故障
}
if (x || y) break; // 如果已经确定故障类型,提前退出
}
if (x) res[i] = 'X'; // 常亮故障
elseif (y) res[i] = 'x'; // 不亮故障
}
cout << res << endl; // 输出结果
return0;
}
领取专属 10元无门槛券
私享最新 技术干货