201909-3 《字符画》 简单易懂,使用最简单的代码

  • Post author:
  • Post category:其他


在这里插入图片描述


不追求最精简的代码,追求最易读懂的代码,努力让读者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 版权协议,转载请附上原文出处链接和本声明。