CCF认证201909-3字符画

原文链接

我的个人博客

原题链接

CCF认证201909-3字符画

思路

  不得不说,这个题是真的恶心。这么多字还说不清楚。大概考的是心态吧。。。。题目本身不难,读懂它的要求就好。
  题目的大概意思是,可以通过\x1b[42;2;R;G;Bm改变终端的背景色。现在给你一个图片中每一个像素的值,由RGB三个颜色组成。将大的图片分割成p*q大小的小块。每一个小块的颜色,是这个小块中所有像素的平均值(RGB分开计算)。向屏幕中输出一个空格代表一个小块。小块的颜色就是之前计算的平均的颜色。
  控制当前小块颜色的字符串,如\x1b[42;2;0;0;0m,再加上一个空格。就可以控制当前小块的颜色。但是题目是要求将这些本应该直接输出的字符串的每一个字符都变成转义字符然后输出。那么如何将普通的字符,变为十六进制的转移字符就是本题的关键。这里的处理方法是,其中c是要处理的字符串
printf("\\x%02X",c)
比如第一个例子
在这里插入图片描述
  说到这里默默留下了眼泪,幸好不是我今年考的第三题。因为我是真的不知道。
  其实把题目的意思搞清楚就好办很多很多了。记录图片的像素,然后得到每一个小块的像素。假如这一个小块得到的像素为(123,456,789)。那么需要设置的背景\x1b[42;2;123;456;789m。我们需要遍历这个字符串,输出每一个字符的转义序列就是最后的答案。
  有几点是题目要求我们注意的:
在这里插入图片描述
  翻译成人话就是
第一:如果当前小块的颜色和前一个小块的颜色相同,则直接输出空格,不需要在输出颜色
第二:如果当前小块颜色和默认值相同(也就是黑色(0,0,0)),使用重置转义\x1b[0m,而不需要使用\x1b[48;2;0;0;0m这种方式去改变
第三:在每一行字符输出后,如果当前的颜色不是默认值,则需要重置终端的颜色,也就是输出\x1b[0m

代码

  这里的代码参考了CSDN博主「日沉云起」的思路,在此表示感谢!

#include <bits/stdc++.h>
using namespace std;

void output(string& s, vector<int> rgb = {0, 0, 0}) {  //输出
    for (char c : s)
        if (c == 'R' || c == 'G' || c == 'B') {  //是RGB数值
        	//将10进制的颜色变为字符串 
            string t = to_string(rgb[c == 'R' ? 0 : c == 'G' ? 1 : 2]);  //将数值转换成字符串
            for (char cc : t)  //遍历字符串
                printf("\\x%02X", cc);  //输出16进制数
        } else
            printf("\\x%02X", c);  //输出字符的16进制数
}


int main(){
	string back = "\x1b[48;2;R;G;Bm", reset = "\x1b[0m";  //背景色和重置默认值字符串
    int m, n, p, q;
    cin >> m >> n >> p >> q;//输入图的大小
	vector<vector<vector<int> > > image(n);  //图像像素
	string rgb="";
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>rgb;//输入每一块的颜色 
			if(rgb.size() == 2){
				rgb +=  string(5,rgb.back());//#a 变为#aaaaaa 
			}else if(rgb.size() == 4){
				//#abc 变为 #aabbcc 
				rgb = "#" + string(2,rgb[1]) + string(2,rgb[2]) + string(2,rgb[3]);
			} 
			//根据标准的#RGB(六位)得到10进制的(r,g,b)
			vector<int> color(3);
			for(int t=0;t<3;t++){
				color[t] = stoi(rgb.substr(2 * t + 1, 2), 0, 16);//将16进制的字符串转为10进制并返回 
			}
			image[i].push_back(color);//保存图片颜色 
		}
	} 
	vector<int> last{0,0,0},defaultColor = {0,0,0};
	for(int i=0;i<n/q;i++){
		for(int j=0;j<m/p;j++){
			vector<int> cur(3); 
			for(int r = 0; r < q ; r++){
				for(int s = 0; s < p; s++){
					for(int t = 0;t < 3;t++){
						cur[t] += image[i*q + r][j*p +s][t];
					}
				}
			}
			for(int t = 0; t < 3; t++){
				cur[t] /= p*q;//计算平均值 
			}
			if(cur != last){//和前一块颜色不一样才需要输出
				if(cur == defaultColor){//与默认颜色相同 
					output(reset);//使用重置,恢复默认颜色 
				}else{
					output(back,cur);
				} 	
			}
			last = cur;//更新前一个颜色 
			printf("\\x%02X",' ');//输出一个空格(16进制) 
		}
		//输入一行字符后,如果当前的颜色不是默认字符,则重置终端颜色 
		if(last != defaultColor){
			output(reset);//重置背景颜色为默认 
		}
		last =  defaultColor;
		printf("\\x%02X",'\n');//输出换行符 
	} 
	return 0; 
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值