CSP 201909-3 字符画(C)

题目

在这里插入图片描述

解题思路

(先吐槽下这题)这题目是真的出的很恶心,啰嗦一大堆废话,半天讲不到要点上,还把解题关键点说的很分散。最主要是题目逻辑很不清晰,让人理解题目事倍功半,当年考场上啃这题硬是花了半个多小时才“看懂”题目,现在复盘想想可能当时还是没看透题目。其实这题真正读懂了题目会发现这题其实不难,基本没有涉及算法,只是处理字符繁杂了些。
下面主要讲下真正的题意:

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)

在这里插入图片描述
如果代码有写的不好的地方,欢迎大家指出,共同学习进步~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值