CCF认证201909-3字符画

题目描述

201909-3字符画

算法设计+题目分析

吐槽一下
题目极其复杂,做的时候看了十几分钟题目愣是没看懂,去网上看了其他同学做的一些blog,还是没看懂。。。然后对着感谢链接里的同学的代码梳理了一下,才明白题目要干嘛,由于个人原因,只能在Visual C++ 6.0里操作,所以很多C++11的函数不能用,但也正是不能用,对于早期的人来说能理解得更透一些。

算法设计+题目分析
1、 题目里说的什么字符画根本就不用管,这就是一个最低级的图像压缩的思想,就是对一块内的RGB三个通道求平均值;
2、所有的输出前都要有/x;
3、空格、换行、ESC都需要用ASCII十六进制输出;
4、算出一块的RGB平均值后,若不等于上一块的RGB且不等于初始值(全零),则用ASCII输出这个背景色的命令;若不等于上一块的RGB但等于初始值(全零),输出reset重置的ASCII;
5、每块后输出一个空格,每一行输出一个换行符;
5、每一行输出换行符之前,要判断当前的RGB与start(全零)是否相同,不同要输出重置的ASCII。

几个核心点
1、输入的RGB三通道为16进制字符串,需先转为10进制整型;
2、输出时注意\x转义符和按照16进制输出

注意点+记录点

1. struct初始化的时候不可赋值
2. 在早期C++编译器(Visual C++6.0)中如何整数转换成字符串

#include <sstream>
#include <string>
using namespace std;
int main(){
	stringsteam ss;
	string t;
	int a=0;
	ss<<a;
	t=ss.str();
	return 0;
}

3. 单引号和双引号的区别
在C中单引号实际上是一个整数值(ASCII),'A’和"A"是两个不同的,'A’的长度是1,"A"的长度是2
4. 如何输出16进制的ASCII

printf("\\x%02X", s[i])

\x的第一个右斜杠为转义符,%02X为输出16进制数,且少于2位时,补0

代码(100分)

环境
Visual C++6.0

#include <vector>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>

using namespace std;
struct node{
	int R, G, B;
};
const int MAXN=2000;
node image[MAXN][MAXN];//图片矩阵
int X16_to_10(string s){//将16进制的字符串转为10进制整型
	int a,b;
	if (s[0]>='A' && s[0]<='Z') a=((s[0]-'A')+10)*16;
	if (s[0]>='a' && s[0]<='z') a=((s[0]-'a')+10)*16;
	if (s[0]>='0' && s[0]<='9') a=(s[0]-'0')*16;

	if (s[1]>='A' && s[1]<='Z') b=s[1]-'A'+10;
	if (s[1]>='a' && s[1]<='z') b=s[1]-'a'+10; 
	if (s[1]>='0' && s[1]<='9') b=s[1]-'0';
	//cout<<a+b<<endl;
	return a+b;
}

void output(string s, node cur){
	for (int i=0; i<s.size(); i++){//找到RGB三个字符的位置
		string t;
		stringstream ss;
		if (s[i]=='R' || s[i]=='G' || s[i]=='B'){
			if(s[i]=='R') ss<<cur.R;
			if(s[i]=='G') ss<<cur.G;
			if(s[i]=='B') ss<<cur.B;
			t=ss.str();
			for (int j=0; j<t.size(); j++) printf("\\x%02X", t[j]);//按输出16进制输出
		}else printf("\\x%02X", s[i]);		
	}
}

void output2(string s){
	for (int i=0; i<s.size(); i++){
		printf("\\x%02X", s[i]);		
	}
}

int main(){
	//freopen("C:\\input.txt", "r", stdin);
	string back="\x1b[48;2;R;G;Bm";//背景色
	string reset="\x1b[0m";//重置
	int m, n, p, q;//图片宽高和块宽高
	cin>>m>>n>>p>>q;
	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[1]);//#a变为#aaaaaa
			if (rgb.size()==4) rgb="#"+string(2,rgb[1])+string(2,rgb[2])+string(2,rgb[3]);//#abc变为#aabbcc
			//cout<<rgb<<endl;
			image[i][j].R=X16_to_10(rgb.substr(1, 2));
			image[i][j].G=X16_to_10(rgb.substr(3, 2));
			image[i][j].B=X16_to_10(rgb.substr(5, 2));
		}
	}
	node last, start;
	last.R=last.G=last.B=start.R=start.G=start.B=0;
	for (int ii=0; ii<n/q; ii++){//遍历每一个块
		for (int jj=0; jj<m/p; jj++){
			node cur;
			cur.R=cur.G=cur.B=0;
			for (int r=0; r<q; r++){//计算块内RGB之和
				for (int s=0; s<p; s++){
					cur.R+=image[ii*q+r][jj*p+s].R;
					cur.G+=image[ii*q+r][jj*p+s].G;
					cur.B+=image[ii*q+r][jj*p+s].B;
				}
			}
			cur.R /=p*q;//求平均
			cur.G /=p*q;
			cur.B /=p*q;
			if(cur.R!=last.R || cur.G!=last.G || cur.B!=last.B){
				if (cur.R==start.R && cur.G==start.G && cur.B==start.B) output2(reset);
				else output(back, cur);
			}
			last.R=cur.R;//更新last的状态为cur
			last.G=cur.G;
			last.B=cur.B;
			printf("\\x%02X", ' ');
		}
		if (last.R!=start.R || last.G!=start.G || last.B!=start.B) output2(reset);//每一行后如果不一样,就重置
		last.R=start.R;
		last.G=start.G;
		last.B=start.B;
		printf("\\x%02X", '\n');//输出换行符
	}

	return 0;
}

感谢链接

非常感谢这位同学的代码,大家可以去看看,思路一样的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值