不追求最精简的代码,追求最易读懂的代码,努力让读者understand,自己再写出代码
一、审题
按照题目的意思,每行输入的区域颜色,没有区分前景色,背景色。题目更改的都是背景色,因此默认都只更改背景色。
1、初始时终端的前景色和背景色都为默认值(前景白色,背景黑色)
如果第一块区域计算的前景色或背景色为默认值,则不需要输出到终端,但是要输出空格。
2、如果下一个字符和颜色刚好与默认值完全相同,你应当直接使用重置转义序列,而非手动更改颜色。
3、 如果某个字符的前景色/背景色与其前一个字符相同,或者对颜色的更改并不影响最终的显示效果,则不应该出现更改这个属性的控制序列。
能省就省,不要忘记输出空格。
4、在输每一行字符后,如果终端颜色不是默认值,你应该重置终端的颜色状态。
每一行最后也需要输出换行符 \n
5、需要处理特殊情况#aabbcc可以写成#abc,#aaaaaa可以写成#a
就三种情况,单独拿出来处理一下okk
二、算法策略
1、颜色存储,颜色换算,使用 dot [m][n] 标记任意坐标的颜色。
struct dot{
int R;
int G;
int B;
dot(int a,int b,int c){
R = a;
G = b;
B = c;
}
}
将string转换为 dot,单独拿出来一个函数。
3、区域计算,区域数量为(m×n)/(p×q),行数为n/q,使用vector 链接,注意区分行就行。
4、初始背景色,前景色,在每行开始的时候设置为前驱,标记前驱来省略对颜色的更改。
5、模拟的时候不要漏掉题目给的情况,宏观上严密把控后,再局部实现。
void outputRGB()
{
int size = list.size(); //区域的块数
int gap = m/p; // 每行gap个区域
int i;
dot pre; //前一个区域
dot curr; //当前区域
for(i=0;i<size;i++)
{
curr = list[i];
if(i%gap == 0) // 1、每行第一个设置前驱为默认背景色
pre = defaultDot;
if(isEqual(curr,pre)) // 2、当前颜色和前驱颜色相同,不做更改直接输出一个空格
outputSpace();
else if(isEqual(curr,defaultDot)){ // 3、当前颜色为默认背景颜色
outputDefaultRGB(); // 输出重置终端,而不是当前颜色
outputSpace(); //输出一个空格
}
else{ // 普通输出
outputSingleRGB(curr);
}
if( (i+1)%gap ==0 && !isEqual(curr,defaultDot)){ // 每行最后一个不是默认颜色
outputDefaultRGB();
}
if( (i+1)%gap == 0 ) // 每行最后一个
printf(R"(\x0A)"); //输出'\n'
pre = curr; // 更新前驱
}
}
确保上诉不漏掉题目所给出的情况后,再一一实现子函数。
最终AC代码如下。
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
int m,n;
int p,q;
struct dot{
int R;
int G;
int B;
dot(int a,int b,int c){
R = a;
G = b;
B = c;
}
dot(){
R=G=B=0;
}
};
dot arr[1100][2000];
dot defaultDot(0,0,0); // 默认背景色
vector<dot> list;
int toAscii(char ch)
{
if(ch>='a')
return ch-'a'+10;
else
return ch-'0';
}
dot strToDot(string str)
{
str.erase(str.begin()); //删除前导#
dot res;
int len = str.length();
if(len == 6){
res.R = toAscii(str[0])*16 + toAscii(str[1]);
res.G = toAscii(str[2])*16 + toAscii(str[3]);
res.B = toAscii(str[4])*16 + toAscii(str[5]);
}
else if(len == 1){
str += str[0];
res.R = res.G = res.B = toAscii(str[0])*16 + toAscii(str[1]);
}
else{ //len = 3
res.R = toAscii(str[0])*16 + toAscii(str[0]);
res.G = toAscii(str[1])*16 + toAscii(str[1]);
res.B = toAscii(str[2])*16 + toAscii(str[2]);
}
return res;
}
dot countDot(int row,int endRow,int col,int endCol)
{
dot res;
int i,j;
for(i=row;i<endRow;i++)
for(j=col;j<endCol;j++)
{
res.R += arr[i][j].R;
res.G += arr[i][j].G;
res.B += arr[i][j].B;
}
int area = (endRow-row)*(endCol-col);
res.R /= area;
res.G /= area;
res.B /= area;
return res;
}
bool isEqual(dot a,dot b)
{
return (a.R==b.R && a.G==b.G && a.B==b.B);
}
void outputDefaultRGB()
{
printf(R"(\x1B\x5B\x30\x6D)"); // ESC[0m
}
void outputNumber(int num)
{
string str;
str = to_string(num);
for(char i : str)
{
int a = int(i); //转化为ascii码
printf(R"(\x)");
printf("%X",a);
}
}
void outputSingleRGB(dot curr)
{
printf(R"(\x1B\x5B\x34\x38\x3B\x32\x3B)"); // ESC[48;2;
outputNumber(curr.R);
printf(R"(\x3B)");
outputNumber(curr.G);
printf(R"(\x3B)");
outputNumber(curr.B);
printf(R"(\x6D\x20)"); // m+space
}
void outputSpace()
{
printf(R"(\x20)");
}
void outputRGB()
{
int size = list.size();
int gap = m/p; // 每行gap个区域
int i;
dot pre; //前一个区域
dot curr; //当前区域
for(i=0;i<size;i++)
{
curr = list[i];
if(i%gap == 0) // 1、每行第一个设置前驱为默认背景色
pre = defaultDot;
if(isEqual(curr,pre)) // 2、当前颜色和前驱颜色相同,不做更改直接输出一个空格
outputSpace();
else if(isEqual(curr,defaultDot)){ // 3、当前颜色为默认背景颜色
outputDefaultRGB(); // 输出重置终端,而不是当前颜色
outputSpace(); //输出一个空格
}
else{ // 普通输出
outputSingleRGB(curr);
}
if( (i+1)%gap ==0 && !isEqual(curr,defaultDot)){ // 每行最后一个不是默认颜色
outputDefaultRGB();
}
if( (i+1)%gap == 0 ) // 每行最后一个
printf(R"(\x0A)"); //输出'\n'
pre = curr; // 更新前驱
}
}
int main() {
cin>>m>>n;
cin>>p>>q;
int i,j;
string str;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>str;
arr[i][j] = strToDot(str);
}
i = j = 1;
while( i<=n )
{
dot t = countDot(i,i+q,j,j+p);
list.push_back(t);
j += p;
if( j > m )
{
j = 1;
i += q;
}
}
outputRGB();
return 0;
}
版权声明:本文为qq_41173604原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。