CCF CSP 20190903 字符画 100分

题目概述

CCF的第三题一般为数据/字符串处理题,比第一题和第二题要难很多。该题不需要用到很难的数据结构,但是处理的数据比较繁琐,并且对输出格式要求十分的严格,稍微不一样就不得分,所以一定要细心的读完题目,认真了解该题要我们做什么后再开始编程。另外第三题给的测试数据集一般是不够用的,我们要多设计一些测试数据集,专挑特殊情况的测试集测试才能减少错误的发生。

第三题字符画大致题意为将一张大图分成若干个小块,计算每一小块的平均像素,并将处理后的平均像素按一定顺序输出。这道题相当于是对图片进行压缩的操作。

关于该题的描述废话有点多,比如该题根本不会用到前景色,但是花费了很长篇幅来叙述前景色,对考生进行了误导,加大了题目的难度。

 

输入输出

输入格式为第一行输入大图的宽m和高n,第二行输入小块的宽p和高q,接下来的m*n行依次输入大图的像素,按从左到右,从上到下的顺序输入。

输出格式为依次输出小块的平均像素,按从左到右,从上到下的顺序输出为一行,每次到行尾时输出/x0A表示换行。并按照题目要求在相应位置加入转义序列ESC[48;2;...m(\x1B\x5B\x34\x38\x3B\x32\x3B...\x6D)或ESC[0m(即\x1B\x5B\x30\x6D)。

输出格式要注意以下几点:

  1. 初始时终端的背景色都为默认值(背景黑色);
  2. 如果下一个字符的颜色刚好与默认值完全相同,应当直接使用重置转义序列ESC[0m(即\x1B\x5B\x30\x6D),而非手动更改颜色;
  3. 如果某个字符的背景色与其前一个字符相同则直接在前一个字符后输入“空格”(\x20);
  4. 在每行(遇到/x0A几位换行)结尾处,如果终端颜色不是默认值,应该重置终端的颜色状态。

 

思路

  1. 根据题中所给的m和n的取值范围,这里可以创建一个三维数组unsigned char pixel[1080][1920][3]来存储图片像素R,G,B。存储时需要将#xxxxxx转换为对应的R,G,B,并对特殊情况#x和#xxx做相应的处理。
  2. 计算每一小块像素的平均值,并将计算出的像素值的ASCII编码转义为16进制编码形式,如像素为255,55,5需要转义为/x32/x35/x35,/x35/x35,/x35。
  3. 定义PR,PG,PB保存上一次像素值,每进行第一行或者新一行的运算时需要将PR,PG,PB初始化为默认值0。然后将计算的像素平均值与PR,PG,PB或者默认值0,0,0比较来输出相应的格式

具体解释请看代码分析:

#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
using namespace std;
unsigned char pixel[1080][1920][3];
//记录图片的宽和高
int m, n;
//记录小块图片的宽和高
int p, q;

//将输入的像素计算为具体数值
unsigned char compute(char c1, char c2)
{
	unsigned char ch = 0;
	if (c1 >= 'a')
		ch = (c1 - 'a' + 10) * 16;
	else
		ch = (c1 - '0') * 16;

	if (c2 >= 'a')
		ch += c2 - 'a' + 10;
	else
		ch += c2 - '0';
	return ch;
}

//将小块的平均像素转换为合适的格式
void transfer(int num1, string &num2)
{
	stringstream on;
	on << num1;
	on >> num2;
	on.clear();
	if (num2.size() == 1)
	{
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[0];
	}
	else if (num2.size() == 2)
	{
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[0];
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[1];
	}
	else
	{
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[0];
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[1];
		on << "\\x";
		on << hex << setw(2) << uppercase << (int)num2[2];
	}
	on >> num2;
}

int main()
{
	cin >> m >> n >> p >> q;
	//RGB分别用于记录三原色的数值,N为小块图片的像素数
	int R, G, B, N = p * q;
	//SR SG SB为R G B对应的16进制字符串形式
	string SR, SG, SB;
	//PR PG PB分别用于记录上一小块图片的三原色的数值,初始为0,表默认值
	int PR = 0, PG = 0, PB = 0;
	//color用于输入像素#aaaaaa
	string color;

	//输入像素,并将输入的像素处理好后存入到pixel数组
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> color;
			//判断特殊情况如#a,将其改为#aaaaaa
			if (color.size() == 2)
				color += string(5, color[1]);
			//判断特殊情况如#aaa,将其改为#aaaaaa
			else if (color.size() == 4)
				color = string(1, color[0]) + string(2, color[1]) + string(2, color[2]) + string(2, color[3]);
			//cout << color << endl;
			pixel[i][j][0] = compute(color[1], color[2]);
			pixel[i][j][1] = compute(color[3], color[4]);
			pixel[i][j][2] = compute(color[5], color[6]);
		}
	}
	//进行循环输出小块图片的平均像素,n/q行
	for (int i = 0; i < n / q; i++)
	{
		//每进行新一行的计算时都需要把PR PG PB重置
		PR = 0, PG = 0, PB = 0;
		//共有m/p列
		for (int j = 0; j < m / p; j++)
		{
			//每进行一小块像素计算时,都需要把像素R,G,B重置
			R = 0, G = 0, B = 0;
			//计算每一小块的像素
			for (int k = i * q; k < i * q + q; k++)
			{
				for (int h = j * p; h < j * p + p; h++)
				{
					R += pixel[k][h][0];
					G += pixel[k][h][1];
					B += pixel[k][h][2];
				}
			}
			//对每一小块的像素去平均准,并转换为字符串形式
			R /= N; G /= N; B /= N;
			transfer(R, SR);  transfer(G, SG);  transfer(B, SB);

			//将计算的像素平均值与PR,PG,PB或者默认值0,0,0比较来输出对应数据格式
			if (!(R == PR && G == PG && B == PB))
			{
				if (R == 0 && G == 0 && B == 0)
					cout << "\\x1B\\x5B" << "\\x30\\x6D";
				else
					cout << "\\x1B\\x5B\\x34\\x38\\x3B\\x32\\x3B" << SR << "\\x3B" << SG << "\\x3B" << SB << "\\x6D";
			}
			cout << "\\x20";
			PR = R, PG = G, PB = B;

			//在每行结尾处,如果终端颜色不是默认值,应该重置终端的颜色状态。
			if (j == m / p - 1 && !(R == 0 && G == 0 && B == 0))
				cout << "\\x1B\\x5B\\x30\\x6D";
		}
		//换行
		cout << "\\x0A";
	}
	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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章