CCF-CSP认证考试准备第十三天:201909-3 字符画(大模拟)


### Day13:1.201909-3
#### 1.201909-3:字符画(大模拟)
(1)自己写出来是0分,但是还是没有找到问题所在,但整体思路没有问题,步骤一处理像素颜色输入(转化格式) 和步骤二计算块像素平均值都调试实现了,步骤三输出格式转变可能出现了问题,直接学习满分代码思路和写法。
(2)代码:
```
#include <bits/stdc++.h>

using namespace std;

struct RGB{
    int R;
    int G;
    int B;//不习惯写数组,还是分开写成三个 
}; 

int char2digit(char c){//单个16进制字符 
    if(c>='0' && c<='9')    return c-'0';
    else if(c>='a' && c<='f')    return c-'a'+10;
    else if(c>='A' && c<='F')    return c-'A'+10;
}

int string2digit(string s){//多个16进制字符组成的字符串
    int sum=0;
    for(int i=0;i<2;i++){
        sum=sum*16+char2digit(s[i]);
    }
    return sum;
}

bool isEqual(const RGB& a,const RGB& b){
    if(a.R==b.R && a.G==b.G && a.B==b.B)    return true;
    return false;
}

void output1(string s){
    for(int i=0;i<s.size();i++){
        cout<<"\\x"<<hex<<uppercase<<setw(2)<<int(s[i]);//如果进行十六进制输出 
    }
}

void output2(int num)
{
    string s = to_string(num);  // 保持行为与 printstr 一致
    for (int i = 0; i < s.size(); i++)
    {
        cout << "\\x" << hex << uppercase << setw(2) << int(s[i]);  // 输出字符的 ASCII 码的十六进制表示
    }
}

int main(){
    ios::sync_with_stdio(false);
    int n,m,p,q;
    cin>>m>>n>>p>>q;
    vector<vector<RGB>> vImages(n,vector<RGB>(m));
    //处理像素颜色输入(转化格式) 
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            string str;
            cin>>str;
            str.erase(0,1);
            if(str.size()==1){
                str=string(6,str[0]);//string类的构造函数 
            }
            else if(str.size()==3){
                str=string(2,str[0])+string(2,str[1])+string(2,str[2]);
            }
            RGB t;
            t.R=string2digit(str.substr(0,2));
            t.G=string2digit(str.substr(2,2));
            t.B=string2digit(str.substr(4,2));
            vImages[i][j]=t;
        }
    }
    //计算块像素平均值
    int block_n=n/q;
    int block_m=m/p;//单独算一下 
    vector<vector<RGB>> vBlocks(block_n,vector<RGB>(block_m));
    for(int i=0;i<block_n;i++){
        for(int j=0;j<block_m;j++){
            int RR=0,GG=0,BB=0; 
            for(int k=i*q;k<(i+1)*q;k++){
                for(int z=j*p;z<(j+1)*p;z++){
                    RR+=vImages[k][z].R;
                    GG+=vImages[k][z].G;
                    BB+=vImages[k][z].B;
                }
            }
            vBlocks[i][j].R=RR/(p*q);
            vBlocks[i][j].G=GG/(p*q);
            vBlocks[i][j].B=BB/(p*q);
        }
    }
    //输出格式转变(重点)
    RGB last={0,0,0},init={0,0,0}; //重点构造,原来代码没有初始化这边导致不好判断,但记得加上结构体比较函数 
    for(int i=0;i<block_n;i++){
        RGB cur={0,0,0};
        for(int j=0;j<block_m;j++){
            cur=vBlocks[i][j];//现在的
            if(!isEqual(cur,last)){//先判断如果某个字符的前景色/背景色与其前一个字符相同,而不是先判断默认,因为上一个颜色也可能是默认 
                if(isEqual(cur,init)){//如果下一个字符的颜色刚好与默认值完全相同
                    cout<<"\\x1B\\x5B\\x30\\x6D";//ESC[0m
                    last=init;//这个赋值很关键 
                }
                else{
                    //关注如何输出 
//0分 
//                    cout<<"\\x1B\\x5B\\34\\x38\\x3B\\x32\\x3B";
//                    output2(cur.R);
//                    cout<<"\\x3B";//;
//                    output2(cur.G);
//                    cout<<"\\x3B";//;
//                    output2(cur.B);
//                    cout<<"\\x6D";//m
//满分                    
                    cout<<"\\x1B"; 
                    output1("[48;2;" + to_string(cur.R) + ";" + to_string(cur.G) + ";" + to_string(cur.B) + "m");
                    last=cur;
                }
            } 
            cout<<"\\x20";//一个块处理完都要输出一个空格
        }
        if(!isEqual(last,init)){//每行输出完后判断如果终端颜色不是默认值,你应该重置终端的颜色状态 
            cout<<"\\x1B\\x5B\\x30\\x6D";//ESC[0m
            last=init;//这个赋值很容易遗漏 
        }
        cout<<"\\x0A";//换行,一般都是最后做 
    }
    return 0;
}
```
(3)
**重点错误**:
1.**思路逻辑错误**:先判断如果某个字符的前景色/背景色与其前一个字符相同,而不是先判断默认,因为上一个颜色也可能是默认 ,这个判断思路一开始写错了,且判断是默认值了或者每一行最后不是默认,last要赋值init
2.**判断特殊条件方法错误**:一开始用bool值和逐个判断RGB是否为0来排除特殊条件,但是会遗漏,且无法把默认值赋给上一个,所以这种**跟前一个比较的题要构造last和cur,并写出对应的isEqual函数(结构体需要)**
3.**题目理解误差**:空格是每个块设置完都要输出,所以是最内层循环最后输出,换行是最后输出(比重置终端的颜色状态还后面,换行基本是最后一个),所以是每一行结束输出(内层循环遍历完成)
**重点学习输入输出**:
1.原来处理像素颜色输入(转化格式)是创建个string对象然后append方法改变再赋值,但是可以直接string类构造对象直接赋值
2.尽量写单个16进制字符转整数(**基础函数**),然后再写一个函数16进制字符串转整数(迭代),或者stoi(str.substr(0,2),nullptr,16);(stoi不仅可以转为10进制数,还能转为16进制数)
3.**16进制的输出**:
`cout<<"\\x"<<hex<<uppercase<<setw(2)<<int(s[i]);//如果进行十六进制输出 `
**注意**:`\x1B`之类的输出要写成`\\x1B`,16进制输出要加上hex,后面大小写和字宽
4.可以直接写成字符串拼接的形式,而不一个一个输出(**待解决的问题**):
`output1("[48;2;" + to_string(cur.R) + ";" + to_string(cur.G) + ";" + to_string(cur.B) + "m");`
(4)本题一开始被干扰了:- `ESC [ 38; 2; R; G; B m` 更改终端的**前景色(字符的颜色)** 为 (R,G,B)这个根本没有用到,且本题难点就是字符串的格式输入输出以及16进制的字符与16进制的数及10进制的数之间的转换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值