题解:B3979 [信息与未来 2024] 红绿灯
DFs_YYDS
·
·
题解
题目传送门
题目大意
给你红绿灯在显示 n 次数字时,亮了哪些数码管,问你这些数码管有没有常亮(即无论什么数字都会亮)或不亮(即无论什么数字都不亮)。
方法一(不推荐)
具体思路
按照题意模拟。
## 完整代码
```cpp
#include<bits/stdc++.h>//万能头。
using namespace std;
char ans[10];//数码管的状态,由于题目中说常亮用大写X,不亮用小写x,没发现故障用-,所以用字符数组来表示。
string book[10]={"ABCDEF ","BC ","ABGED ","ABGCD ","FGBC ","AFGCD ","AFDECG ","ABC ","ABCDEFG ","ABCDFG "};//book[i]表示显示第i个数需要显示的数码管编号。
int main(){//主函数。
int n;//n次记录。
cin>>n;//输入n。
for(int i=0;i<7;i++)ans[i]='-';//刚开始将7个数码管的状态初始化为-,没发现任何故障。
while(n--){//循环n次。
string s;//由于日志是由数字和字母组成的,中间又没有空格,所以用字符串存储比较方便。
cin>>s;//输入字符串s。
int x=s[0]-'0'/*本次记录的数字*/,len=s.size()/*字符串的长度*/;
//处理常亮的情况。
for(int i=1;i<len;i++){//循环这次记录的字符串,注意从1开始,因为前面还有一位是数字。
int flag=1;//是否损坏。
for(int j=0;book[x][j]!=' ';j++){//由于显示每个数字需要的数码管不一样,所以统一最后有一个空格。
if(book[x][j]==s[i]){//如果这个数码管本来就需要亮。
flag=0;//没有损坏。
break;//直接跳出循环,减少时间。
}
}
if(flag)/*如果这个数码管不需要亮,但它亮了*/ans[s[i]-'A']='X';//这个数码管的状态就是常亮。
}
//处理不亮的情况。
for(int i=0;book[x][i]!=' ';i++){//循环显示x需要的数码管,遇到空格结束。
int flag=1;//是否损坏。
for(int j=1;j<len;j++){//循环日志中记录的亮的数码管,注意从1开始。
if(book[x][i]==s[j]){//如果这个数码管在记录中确实亮了。
flag=0;//没有损坏。
break;//跳出循环。
}
}
if(flag)/*如果这个数码管需要亮,但它没亮*/ans[book[x][i]-'A']='x';//这个数码管的状态就是不亮。
}
}
for(int i=0;i<7;i++)cout<<ans[i];//输出ans数组。
return 0;//好习惯。
}
```
但是代码未免有些太长了,怎么缩短呢?
# 方法二(推荐)
## 具体思路
方法一代码长的原因在于,用了两个循环双重循环分别处理常亮和不亮的情况,如果我们将常亮和不亮在同一个循环中一起处理,代码就会缩短很多。
参考方法一,使用数组把显示每个数字需要亮的数码管存起来。但是跟方法一不一样的是,我们用的是 `int` 的二维数组(`bool` 也行)来存。$book_{i,j}$ 表示在显示数字 $i$ 时第 $j$ 个数码管是否需要亮,如果是 $1$ 表示需要亮,如果是 $0$ 表示不需要亮。
同样,在 $n$ 个日志中。先建一个数组 $a$,$a_i$ 表示第 $i$ 个数码管是否亮了。然后循环每个数码管,如果 $a_j$ 为 $1$ 但 $book_{x,j}$ 为 $0$,也就是说第 $j$ 个数码管不应该亮但是亮了,这个数码管就是常亮的;如果$book_{x,j}$ 为 $1$ 但 $a_j$ 为 $0$,也就是说第 $j$ 个数码管应该亮但是没亮,这个数码管就是不亮的,将状态存入答案数组 $ans$ 中。
这样,我们就将两个循环缩减为一个循环,大大的减少了代码量。
## 完整代码
```cpp
#include<bits/stdc++.h>
using namespace std;
char ans[10];//答案数组。
int book[10][7]={1,1,1,1,1,1,0,
0,1,1,0,0,0,0,
1,1,0,1,1,0,1,
1,1,1,1,0,0,1,
0,1,1,0,0,1,1,
1,0,1,1,0,1,1,
1,0,1,1,1,1,1,
1,1,1,0,0,0,0,
1,1,1,1,1,1,1,
1,1,1,1,0,1,1,};
int main(){
int n;
cin>>n;
for(int i=0;i<7;i++)ans[i]='-';//初始化。
for(int i=0;i<n;i++){
string s;
cin>>s;
int x=s[0]-'0',len=s.size();
int a[10];//实际上a数组开到7就行了,这里开10保险一点。
for(int j=0;j<7;j++)a[j]=0;//在循环内定义数组要先全部初始化为0。
for(int j=1;j<len;j++)a[s[j]-'A']=1;//这个数码管亮了。
for(int j=0;j<7;j++){
if(a[j]==1&&book[x][j]==0)ans[j]='X';//如果这个数码管亮了但是实际上不应该亮,这个数码管就是常亮的。
if(a[j]==0&&book[x][j]==1)ans[j]='x';//如果这个数码管没亮但是实际上应该亮,这个数码管就是不亮的。
}
}
for(int i=0;i<7;i++)cout<<ans[i];//输出答案数组。
return 0;//华丽结束。
}
```
如果你还觉得长是因为 $book$ 数组的原因,我们将 $book$ 数组放到一行,就不觉得长了。
## 最终完整代码
```cpp
#include<bits/stdc++.h>
using namespace std;
char ans[10];//答案数组。
int book[10][7]={1,1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,0,0,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,};
int main(){
int n;
cin>>n;
for(int i=0;i<7;i++)ans[i]='-';//初始化。
for(int i=0;i<n;i++){
string s;
cin>>s;
int x=s[0]-'0',len=s.size();
int a[10];//实际上a数组开到7就行了,这里开10保险一点。
for(int j=0;j<7;j++)a[j]=0;//在循环内定义数组要先全部初始化为0。
for(int j=1;j<len;j++)a[s[j]-'A']=1;//这个数码管亮了。
for(int j=0;j<7;j++){
if(a[j]==1&&book[x][j]==0)ans[j]='X';//如果这个数码管亮了但是实际上不应该亮,这个数码管就是常亮的。
if(a[j]==0&&book[x][j]==1)ans[j]='x';//如果这个数码管没亮但是实际上应该亮,这个数码管就是不亮的。
}
}
for(int i=0;i<7;i++)cout<<ans[i];//输出答案数组。
return 0;//完结撒花!
}
```