题目
解题思路
(先吐槽下这题)这题目是真的出的很恶心,啰嗦一大堆废话,半天讲不到要点上,还把解题关键点说的很分散。最主要是题目逻辑很不清晰,让人理解题目事倍功半,当年考场上啃这题硬是花了半个多小时才“看懂”题目,现在复盘想想可能当时还是没看透题目。其实这题真正读懂了题目会发现这题其实不难,基本没有涉及算法,只是处理字符繁杂了些。
下面主要讲下真正的题意:
1.首先这题开始就提到了前景色和背景色,但解题只要用到背景色。前景色只是用来迷惑考生的。背景色是ESC[48;2;R;G;Bm,重置终端颜色是ESC[0m。这题实际上就是一个mn的图片压缩为pq。
2.输入是mn个像素点,而每pq个像素点合成一个像素块。举例:
m=n=4,p=q=2。
那么它压缩之后的像素块应该是这样的:红圈中为一个像素块
3.输入的像素点格式是#abcdef,有两种缩写#a和#abc,应该先把缩写的像素规范化,即变为#aaaaaa和#aabbcc,经验证,输入都是小写的字符。(我一开始还担心会不会有大写的输入,题目中也没有说明)
4.把像素块的平均RGB求出,过程是先把#abcdef变为十进制,再算出平均值,再变为(十进制的)字符串输出,注意这点,我就是因为变为十六进制的字符串输出了,一直是0分。。。
输出时要注意:如果当前的像素块的RGB和前一个像素块的RGB(初始化为0;0;0)相同,则不输出改变序列,只输出一个空格即\x20。如果不同,再判断当前RGB是否和默认RGB即0;0;0相同,如果相同,输出ESC[0m ,转义序列为\x1B\x5B\x30\x6D\x20;不同则输出ESC[48;2;R;G;Bm+空格的转义序列。
5.还有在输出中要注意的是:每个像素块后面要输出一个空格即4中的\x20,总共有mn/pq个空格;每一行像素块后面要判断当前RGB是否和默认相同,不同要输出重置序列ESC[0m,但注意不需要加上空格!!!,只有每个像素块后面才要空格,最后每行的最后要输出一个换行即\x0A,总共有n/q个换行。
6.前面3-5步已经把解题步骤告诉大家了,现在总结下:这题就是根据输入的mn个像素点求出pq个像素块的RGB,再根据规则输出每个像素块的转义序列。这样一说是不是很简单呢?
代码(纯c代码)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
char **str;
int m,n,p,q;
int RGB[3]={0};//色度值
char pre[12]="0;0;0";//前一个颜色块
char background[12]="0;0;0";//默认背景色
void tran(){//将某些简写规范化
int i;
for(i=0;i<m*n;i++){
if(strlen(str[i])==2){
for(int j=2;j<7;j++)
str[i][j]=str[i][1];
}
else if(strlen(str[i])==4){
for(int j=6;j>=2;j--)
str[i][j]=str[i][(j+1)/2];
}
}
}
void HtoD(char *s){//将字符形式的十六进制转为十进制加上。
for(int i=1;i<7;i++){
if(s[i]<='9'&&s[i]>='0')
RGB[(i-1)/2]+=(s[i]-'0')*(int)pow(16,i%2);
else
RGB[(i-1)/2]+=(s[i]-'a'+10)*(int)pow(16,i%2);
}
}
void DtoS(char *s){//将色块的色度由十进制转为字符串
int index=0;
for(int i=0;i<3;i++){
if(RGB[i]<10)
s[index++]=RGB[i]+48;
else if(RGB[i]<100){
s[index++]=RGB[i]/10+48;
s[index++]=RGB[i]%10+48;
}
else{
s[index++]=RGB[i]/100+48;
s[index++]=RGB[i]%100/10+48;
s[index++]=RGB[i]%10+48;
}
if(i!=2)
s[index++]=';';
}
s[index]='\0';
}
void print(char *s,int flag){//输出一个色块的控制序列
printf("\\x1B\\x5B");
if(flag==0)
printf("\\x30\\x6D");
else{
printf("\\x34\\x38\\x3B\\x32\\x3B");
for(int i=0;i<strlen(s);i++)
printf("\\x%X",s[i]);
printf("\\x6D\\x20");
}
}
void work(){
int i=0;
char color[12];//存储当前色块RGB
for(i;i<m*n/p/q;i++){//按顺序处理每个色块
for(int j=i%(m/p)*p;j<i%(m/p)*p+p;j++){
for(int k=i/(m/p)*q;k<i/(m/p)*q+q;k++){
HtoD(str[k*m+j]);//hex->d
}
}
for(int l=0;l<3;l++)
RGB[l]/=p*q;
DtoS(color);//d->(s)hex
//printf("%s\n",color);
/*分析怎么输出这个色块*/
if(strcmp(pre,color)!=0){//当前色块和前一个色块不同
if(strcmp(color,background)==0){//如果和默认背景色相同
print(background,0);
printf("\\x20");
}
else
print(color,1);
}
else//和前一块相同输入一个空格
printf("\\x20");
if((i+1)%(m/p)==0){//判断是否重置终端颜色状态
if(strcmp(color,background)!=0)
print(background,0);
printf("\\x0A");
strcpy(pre,background);
}
else
strcpy(pre,color);//把当前色块复制给pre
color[0]='\0';
memset(RGB,0,sizeof(RGB));
}
}
int main(void){
scanf("%d %d",&m,&n);
scanf("%d %d",&p,&q);
str=(char **)malloc(m*n*sizeof(char *));//动态分配内存
for(int i=0;i<m*n;i++){
str[i]=(char *)malloc(7*sizeof(char));
scanf("%s",str[i]);
}
tran();//规范化处理
work();
return 0;
}
八个测试样例
输入1
1 1
1 1
#010203
输出1
\x1B\x5B\x34\x38\x3B\x32\x3B\x31\x3B\x32\x3B\x33\x6D\x20\x1B\x5B\x30\x6D\x0A
输入2
2 2
1 2
#111111
#0
#000000
#111
输出2
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x20\x1B\x5B\x30\x6D\x0A
输入3
1 1
1 1
#0
输出3
\x20\x0A
输入4
2 2
2 1
#111111
#0
#000000
#111
输出4
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A
输入5
2 2
2 1
#111111
#0
#000000
#000
输出5
\x1B\x5B\x34\x38\x3B\x32\x3B\x38\x3B\x38\x3B\x38\x6D\x20\x1B\x5B\x30\x6D\x0A\x20\x0A
输入6
3 2
1 2
#0
#0
#010101
#010102
#0
#0
输出6
\x1B\x5B\x34\x38\x3B\x32\x3B\x30\x3B\x30\x3B\x31\x6D\x20\x1B\x5B\x30\x6D\x20\x20\x0A
输入7
1 2
1 2
#123456
#abcdef
输出7
\x1B\x5B\x34\x38\x3B\x32\x3B\x39\x34\x3B\x31\x32\x38\x3B\x31\x36\x32\x6D\x20\x1B\x5B\x30\x6D\x0A
输入8
2 1
2 1
#654321
#fedcba
输出8
\x1B\x5B\x34\x38\x3B\x32\x3B\x31\x37\x37\x3B\x31\x34\x33\x3B\x31\x30\x39\x6D\x20\x1B\x5B\x30\x6D\x0A
测试结果(796ms)
如果代码有写的不好的地方,欢迎大家指出,共同学习进步~