CCF-201909-3

CCF上面的题目有一些跟我平时做的算法题很不一样,就比如说这道。这道题可以说是将输入输出的方法考察的淋漓尽致,中间的过程反而不是那么困难了。而且我发现ccf经常出这种背景很长,需要仔细理解的问题,一般第三题之后的题目都呈现这样的特点。

先放题目

我的代码如下,main函数的长度尽量写短了,像这种输入输出比较复杂的题我感觉还是用C++比较简单,因为Java的格式化输入输出我觉得不如C++/C顺手,对字符串的处理整一手sscanf,sprintf(如果在Visual Studio中不想用 sscanf_s就药要在开头加一个宏定义 _CRT_SECURE_NO_WARNINGS),对应的十六进制输入输出就很好用(例如%04x,就是指以小写的4位16进制输出,不足4位补零),代码如下

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<string>
#include<string.h>
using namespace std;

/*test:
2 2
1 2
#111111
#0
#000000
#111
*/

struct pixel{
	int R, G, B;
	pixel(int r, int g, int b) : R(r), G(g), B(b) {};
};

bool equalPixel(pixel A, pixel B) {
	if (A.B == B.B && A.G == B.G && A.R == B.R) {
		return true;
	}
	else
	{
		return false;
	}
}

string toHex(int c) {
	char hex[20];
	if (c / 100 != 0) {	//3位数 
		int h = c / 100;
		int t = (c % 100) / 10;
		int g = c - h * 100 - t * 10;
		sprintf(hex, "\\x3%d\\x3%d\\x3%d", h, t, g);
	}
	else if (c / 10 != 0) {	//2位数 
		int t = c / 10;
		int g = c - 10 * t;
		sprintf(hex, "\\x3%d\\x3%d", t, g);
	}
	else {
		sprintf(hex, "\\x3%d", c);
	}
	return string(hex);
}

pixel getPixel(string s) {
	int length = s.length();
	char fullFormat[8];
	//先将简写形式转化为完全形式,再提取关键字
	if (length == 2) {
		char c;
		sscanf(s.c_str(), "#%c", &c);
		sprintf(fullFormat, "#%c%c%c%c%c%c", c, c, c, c, c, c);
	}
	else if (length == 4) {
		char a, b, c;
		sscanf(s.c_str(), "#%c%c%c", &a, &b, &c);
		sprintf(fullFormat, "#%c%c%c%c%c%c", a, a, b, b, c, c);
	}
	else if (length == 7) {
		strcpy(fullFormat, s.c_str());
	}

	int r, g, b;
	sscanf(fullFormat, "#%02x%02x%02x", &r, &g, &b);
	return pixel(r, g, b);
}

pixel getAverage(vector<vector<pixel>>& pixelMatrix, int iStart, int jStart, int p, int q) {
	int r, g, b;
	r = 0;  g = 0; b = 0;
	int pxnum = p * q;
	for (int i = iStart; i < iStart + q; i++) {
		for (int j = jStart; j < jStart + p; j++) {
			r += pixelMatrix[i][j].R;
			g += pixelMatrix[i][j].G;
			b += pixelMatrix[i][j].B;
		}
	}
	return pixel(r / pxnum, g / pxnum, b / pxnum);
}

vector<vector<pixel>> getBlockMartix(vector<vector<pixel>> &pixelMatrix, int m, int n, int p, int q) {
	//int blockLineNumber = n / q;	//要输出这么多\n
	//int blockRowNumber = m / p;		//一排色块有多少个
	vector<vector<pixel>> blockMatrix;	//色块的数据同样用pixel存储
	for (int i = 0; i < n; i += q) {
		vector<pixel> blockLine;
		for (int j = 0; j < m; j += p) {
			pixel block = getAverage(pixelMatrix, i, j, p, q);
			blockLine.push_back(block);
		}
		blockMatrix.push_back(blockLine);
	}
	return blockMatrix;
}

int main() {
	int m, n;	//图片宽高
	cin >> m >> n;
	int p, q;	//色块宽高
	cin >> p >> q;
	cin.ignore();	//将缓冲区内多出来的回车符消耗掉
	//int pixelNumber = m * n;
	vector<vector<pixel>> pixelMatrix;
	for (int i = 0; i < n; i++) {	//逐行输入
		vector<pixel> pixelLine;
		for (int j = 0; j < m; j++) {
			string colorStr;
			getline(cin, colorStr);
			pixel input = getPixel(colorStr);
			pixelLine.push_back(input);
		}
		pixelMatrix.push_back(pixelLine);
	}
	//到这里像素矩阵就构造完成了
	int blockLineNumber = n / q;	//要输出这么多\n
	int blockRowNumber = m / p;		//一排色块有多少个
	vector<vector<pixel>> blockMatrix;	//色块的数据同样用pixel存储
	blockMatrix = getBlockMartix(pixelMatrix, m, n, p, q);

	//下面开始输出
	pixel lastBlock(0, 0, 0);
	pixel defaultBlock(0, 0, 0);
	for (int i = 0; i < blockLineNumber; i++) {
		for (int j = 0; j < blockRowNumber; j++) {
			pixel thisBlock = blockMatrix[i][j];
			if (equalPixel(thisBlock, lastBlock)) {	//如果与上一个色块相同,直接输出空格即可
				cout << "\\x20";	//输出空格
			}
			else if (equalPixel(thisBlock, defaultBlock)) {	//如果与默认颜色相同,输出重置转义序列
				cout << "\\x1B\\x5B\\x30\\x6D";		//重置转义序列
				cout << "\\x20";	//输出空格
				lastBlock = thisBlock;
			}
			else {
				cout << "\\x1B\\x5B\\x34\\x38\\x3B\\x32\\x3B";	//输出"ESC[48;2;"
				cout << toHex(thisBlock.R);
				cout << "\\x3B";	//输出分号
				cout << toHex(thisBlock.G);
				cout << "\\x3B";	//输出分号
				cout << toHex(thisBlock.B);
				cout << "\\x6D\\x20";		//输出m和空格
				lastBlock = thisBlock;
			}
		}
		if (!equalPixel(lastBlock, defaultBlock)) {	//如果输出完一行后颜色不是默认值,应该恢复终端颜色
			cout << "\\x1B\\x5B\\x30\\x6D";	//重置转义序列
			lastBlock = defaultBlock;
		}
		cout << "\\x0A";	//换行
	}
	return 0;
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注