题解:B3979 [信息与未来 2024] 红绿灯

· · 题解

题目传送门

题目大意

给你红绿灯在显示 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;//完结撒花! } ```