CSP CCF: 201909-3 字符画) (C++)

题目来源

字符画

知识点

  1. C++头文件 #include <stdlib.h> 中的 system(“color xx”); (改成ASCII的输出后后,用不上哦)
    system(“color XX”)函数可用于修改控制台背景及文字颜色。
    第一个X是背景颜色,第二个X是前颜色。(都是16进制的单个字符)
    在我写的代码中没有指明XX。就是默认的前白后黑了。

注意点

  1. ‘\xabcdef’ 输出时, '\x’需要进行转义。 即 ‘\\x’。
  2. 输入中的 #abcdef 中, abcdef是数字或小写字母。
  3. 在将输出转换为ASCII码时, 要记得将16进制数字符串填充成2位的。在我的代码中,特别要注意 RGB某一个为0的情况!

0分(略了)

20分

0分->20分: 之前以为输入的#abcdef中,abcdef会是数字或大写字母。在网上看了大佬的测试样例才意识到是小写字母。
通过了前 20 分的测试点。 (注意点2)
数据特点: m <= 10, n <= 10, p = 1, q = 2;

(有点呆的代码。不太了解c++, 无法熟练运用其中的各种便利的技巧。)

#include <iostream>
#include <fstream>
//#include <stdlib.h>  // sysytem()
#include <map>

using namespace std;

map<char, int> s2t;  // 16转10
map<int, char> t2s;  // 10转16

// 16进制字符串转10进制数字
int sixteen2ten(string sixteen) {
    int num = 0;
    for (char c: sixteen) {
        num = num * 16 + s2t[c];
    }
    return num;
}

// 10进制数字转“\x” + 16进制字符串
string ten2sixteen(int ten) {
    string sixteen = "";

    int shang = 0, yu = 0;
    string invSixteen = "";  // 倒序16进制字符串

    while (ten != 0) {
        yu = ten % 16;
        shang = ten / 16;
        ten = shang;
        invSixteen.push_back(t2s[yu]);
    }

    // 将逆序的调整为正序
    if (invSixteen.size() == 1) {
        sixteen = "0";
    }
    for (int i = invSixteen.size() - 1; i >= 0; --i) {
        sixteen.push_back(invSixteen[i]);
    }

    return "\\x" + sixteen;
}


int main() {
    //ifstream cin("in3.txt");

    //system("color");  // 使终端能根据输出进行颜色变换, 现在这个格式的输出不行。

    // 初始化
    s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['a'] = 10, s2t['b'] = 11, s2t['c'] = 12, s2t['d'] = 13, s2t['e'] = 14, s2t['f'] = 15;  // 注意是小写的
    //s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['A'] = 10, s2t['B'] = 11, s2t['C'] = 12, s2t['D'] = 13, s2t['E'] = 14, s2t['F'] = 15;
    t2s[0] = '0', t2s[1] = '1', t2s[2] = '2', t2s[3] = '3', t2s[4] = '4', t2s[5] = '5', t2s[6] = '6', t2s[7] = '7', t2s[8] = '8', t2s[9] = '9', t2s[10] = 'A', t2s[11] = 'B', t2s[12] = 'C', t2s[13] = 'D', t2s[14] = 'E', t2s[15] = 'F';

    int m, n;  // 宽、高——列、行
    cin>>m>>n;
    int p, q;  // 每一小块的宽、高——列、行
    cin>>p>>q;

    // 存储输入 并 填充
    string inputStr[n][m];  // 存储输入 , 注意这里是 n行 m列 (有点乱哈)
    for (int i = 0; i < n; ++i) {  // 高
        for (int j = 0; j < m; ++j) {  // 宽
            string tmp, t;
            cin>>tmp;

            if (tmp.size() == 2) {  // #a  -> #aaaaaa
                t = tmp;
                for (int ii = 0; ii < 5; ++ii) {
                    t.push_back(tmp[1]);
                }
            }
            else if (tmp.size() == 4) {  // #abc  -> #aabbcc
                t = "#";
                for (int ii = 1; ii <= 3; ++ii) {
                    t.push_back(tmp[ii]);
                    t.push_back(tmp[ii]);
                }
            }
            else {  // #abcdef
                t = tmp;
            }
            //cout<<"i: "<<i<<" j: "<<j<<" t: "<<t<<endl;
            inputStr[i][j] = t;
        }
    }

    //cout<<"OK"<<endl;

    int M = n / q, N = m / p;  // M行N列的色块
    int myRGB[M][N][3];   // 记录每一块的RGB平均值
    //cout<<M<<" "<<N<<endl;

    // 对每个色块中的像素取平均值
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            // get每个色块的像素
            int sumR, sumG, sumB;
            sumR = sumG = sumB = 0;
            //cout<<i<<" "<<j<<endl;
            for (int ii = i * q; ii < i * q + q; ++ii) {
                for (int jj = j * p; jj < j * p + p; ++jj) {
                    string cur = inputStr[ii][jj];
                    string r = cur.substr(1, 2), g = cur.substr(3, 2), b = cur.substr(5, 2);
                    sumR += sixteen2ten(r);
                    sumG += sixteen2ten(g);
                    sumB += sixteen2ten(b);

                    //cout<<"i: "<<ii<<" j: "<<jj<<" "<<sixteen2ten(r)<<" "<<sixteen2ten(g)<<" "<<sixteen2ten(b)<<" * ";
                }
            }
            //cout<<endl<<endl;;
            myRGB[i][j][0] = sumR / (p * q);
            myRGB[i][j][1] = sumG / (p * q);
            myRGB[i][j][2] = sumB / (p * q);
        }
    }

    /*
    // 输出myRGB
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            cout<<myRGB[i][j][0]<<" "<<myRGB[i][j][1]<<" "<<myRGB[i][j][2]<<" * ";
        }cout<<endl;
    }
    */

    // 规划输出 (或许可以和上边的合并哈)
    string ans = "";
    int preR = 0, preG = 0, preB = 0;

    string esc, kongge, kuohao, fenhao, zimum, shuzi48, shuzi0, shuzi2, huanhang;
    esc = ten2sixteen(27);
    kongge = ten2sixteen(' ');
    kuohao = ten2sixteen('[');
    fenhao = ten2sixteen(';');
    zimum = ten2sixteen('m');
    shuzi48 = ten2sixteen('4') + ten2sixteen('8');
    shuzi0 = ten2sixteen('0');
    shuzi2 = ten2sixteen('2');
    huanhang = ten2sixteen('\n');
    string changBackGround = esc + kuohao + shuzi48 + fenhao + shuzi2 + fenhao;  // ESC [ 3 8 ; 2 ;
    string resetBackGround = esc + kuohao + shuzi0 + zimum;  // ESC [ 0 m

    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            // 先判断当前背景RGB是否与前一个相同
            // 相同, 不用改。 只需要添加一个色块
            if (myRGB[i][j][0] == preR && myRGB[i][j][1] == preG && myRGB[i][j][2] == preB) {
                ans += kongge;
                //cout<<"*"<<endl;
            }
            else {  // 不同, 需要改
                // 和默认的一致(0,0,0), 使用重置
                if (myRGB[i][j][0] == 0 && myRGB[i][j][1] == 0 && myRGB[i][j][2] == 0) {
                    ans += resetBackGround;
                    ans += kongge;
                }
                else {
                    // ESC [ ; 4 8 ;
                    ans += changBackGround;

                    int shang, yu;

                    // R ;
                    string curR;
                    shang = myRGB[i][j][0], yu = 0;
                    while (shang != 0) {  // 这样是倒序的
                        yu = shang % 10;
                        shang = shang / 10;
                        curR = ten2sixteen(yu + '0') + curR;  // 这样一下就正序了
                    }
                    ans += curR;
                    //ans += ten2sixteen(myRGB[i][j][0]);
                    ans += fenhao;

                    // G ;
                    string curG;
                    shang = myRGB[i][j][1], yu = 0;
                    while (shang != 0) {
                        yu = shang % 10;
                        shang = shang / 10;
                        curG = ten2sixteen(yu + '0') + curG;
                    }
                    ans += curG;
                    ans += fenhao;

                    // B
                    string curB;
                    shang = myRGB[i][j][2], yu = 0;
                    while (shang != 0) {
                        yu = shang % 10;
                        shang = shang / 10;
                        curB = ten2sixteen(yu + '0') + curB;
                    }
                    ans += curB;
                    //ans += fenhao; /* 不需要!!! B后边不需要分号!!!*/

                    // 添加 m
                    ans += zimum;

                    // 添加色块
                    ans += kongge;
                }

                //
                preR = myRGB[i][j][0];
                preG = myRGB[i][j][1];
                preB = myRGB[i][j][2];
            }
        }

        // 该行结束
        // 1. 还原成默认背景色, 使用重置 2. 修改preRGB 3. 添加换行符
        if (preR != 0 || preG != 0 || preB != 0) {
            ans += resetBackGround;
            preR = preG = preB = 0;
        }
        ans += huanhang;
    }

    cout<<ans;

    return 0;
}

100分

20->100: 在十进制转16进制函数中,自己写代码的时候没有考虑当数字为0要输出\x00。改了这个函数以及主函数中最后一个循环中的RGB部分就好了。(注意点3)

#include <iostream>
#include <fstream>
#include <stdlib.h>  // sysytem()
#include <map>

using namespace std;

map<char, int> s2t;  // 16转10
map<int, char> t2s;  // 10转16

// 16进制字符串转10进制数字
int sixteen2ten(string sixteen) {
    int num = 0;
    for (char c: sixteen) {
        num = num * 16 + s2t[c];
    }
    return num;
}

// 10进制数字转16进制字符串
string ten2sixteen(int ten) {
    string sixteen = "";

    int shang = 0, yu = 0;
    string invSixteen = "";  // 倒序16进制字符串

    while (ten != 0) {
        yu = ten % 16;
        shang = ten / 16;
        ten = shang;
        invSixteen.push_back(t2s[yu]);
    }

    // 将逆序的调整为正序
    if (invSixteen.size() == 1) {
        sixteen = "0";
    }
    if (invSixteen.size() == 0) {  /* 这个不要忘啦 */
        sixteen = "00";
        //cout<<"HELLO"<<endl;
    }
    for (int i = invSixteen.size() - 1; i >= 0; --i) {
        sixteen.push_back(invSixteen[i]);
    }

    return "\\x" + sixteen;
}


int main() {
    //ifstream cin("in3.txt");

    //system("color");  // 使终端能根据输出进行颜色变换

    // 初始化
    s2t['0'] = 0, s2t['1'] = 1, s2t['2'] = 2, s2t['3'] = 3, s2t['4'] = 4, s2t['5'] = 5, s2t['6'] = 6, s2t['7'] = 7, s2t['8'] = 8, s2t['9'] = 9, s2t['a'] = 10, s2t['b'] = 11, s2t['c'] = 12, s2t['d'] = 13, s2t['e'] = 14, s2t['f'] = 15;
    t2s[0] = '0', t2s[1] = '1', t2s[2] = '2', t2s[3] = '3', t2s[4] = '4', t2s[5] = '5', t2s[6] = '6', t2s[7] = '7', t2s[8] = '8', t2s[9] = '9', t2s[10] = 'A', t2s[11] = 'B', t2s[12] = 'C', t2s[13] = 'D', t2s[14] = 'E', t2s[15] = 'F';

    int m, n;  // 宽、高——列、行
    cin>>m>>n;
    int p, q;  // 每一小块的宽、高——列、行
    cin>>p>>q;

    // 存储输入 并 填充
    string inputStr[n][m];  // 存储输入 , 注意这里是 n行 m列 (有点乱哈)
    for (int i = 0; i < n; ++i) {  // 高
        for (int j = 0; j < m; ++j) {  // 宽
            string tmp, t;
            cin>>tmp;

            if (tmp.size() == 2) {  // #a  -> #aaaaaa
                t = tmp;
                for (int ii = 0; ii < 5; ++ii) {
                    t.push_back(tmp[1]);
                }
            }
            else if (tmp.size() == 4) {  // #abc  -> #aabbcc
                t = "#";
                for (int ii = 1; ii <= 3; ++ii) {
                    t.push_back(tmp[ii]);
                    t.push_back(tmp[ii]);
                }
            }
            else {  // #abcdef
                t = tmp;
            }
            //cout<<"i: "<<i<<" j: "<<j<<" t: "<<t<<endl;
            inputStr[i][j] = t;
        }
    }

    //cout<<"OK"<<endl;

    int M = n / q, N = m / p;  // M行N列的色块
    int myRGB[M][N][3];   // 记录每一块的RGB平均值
    //cout<<M<<" "<<N<<endl;

    // 对每个色块中的像素取平均值
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            // get每个色块的像素
            int sumR, sumG, sumB;
            sumR = sumG = sumB = 0;
            //cout<<i<<" "<<j<<endl;
            for (int ii = i * q; ii < i * q + q; ++ii) {
                for (int jj = j * p; jj < j * p + p; ++jj) {
                    string cur = inputStr[ii][jj];
                    string r = cur.substr(1, 2), g = cur.substr(3, 2), b = cur.substr(5, 2);
                    sumR += sixteen2ten(r);
                    sumG += sixteen2ten(g);
                    sumB += sixteen2ten(b);

                    //cout<<"i: "<<ii<<" j: "<<jj<<" "<<sixteen2ten(r)<<" "<<sixteen2ten(g)<<" "<<sixteen2ten(b)<<" * ";
                }
            }
            //cout<<endl<<endl;;
            myRGB[i][j][0] = sumR / (p * q);
            myRGB[i][j][1] = sumG / (p * q);
            myRGB[i][j][2] = sumB / (p * q);
        }
    }

    /*
    // 输出myRGB
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            cout<<myRGB[i][j][0]<<" "<<myRGB[i][j][1]<<" "<<myRGB[i][j][2]<<" * ";
        }cout<<endl;
    }
    */

    // 规划输出
    string ans = "";
    int preR = 0, preG = 0, preB = 0;

    string esc, kongge, kuohao, fenhao, zimum, shuzi48, shuzi0, shuzi2, huanhang;
    esc = ten2sixteen(27);
    kongge = ten2sixteen(' ');
    kuohao = ten2sixteen('[');
    fenhao = ten2sixteen(';');
    zimum = ten2sixteen('m');
    shuzi48 = ten2sixteen('4') + ten2sixteen('8');
    shuzi0 = ten2sixteen('0');
    shuzi2 = ten2sixteen('2');
    huanhang = ten2sixteen('\n');
    string changBackGround = esc + kuohao + shuzi48 + fenhao + shuzi2 + fenhao;  // ESC [ 3 8 ; 2 ;
    string resetBackGround = esc + kuohao + shuzi0 + zimum;  // ESC [ 0 m

    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            // 先判断当前背景RGB是否与前一个相同
            // 相同, 不用改。 只需要添加一个色块
            if (myRGB[i][j][0] == preR && myRGB[i][j][1] == preG && myRGB[i][j][2] == preB) {
                ans += kongge;
                //cout<<"*"<<endl;
            }
            else {  // 不同, 需要改
                // 和默认的一致(0,0,0), 使用重置
                if (myRGB[i][j][0] == 0 && myRGB[i][j][1] == 0 && myRGB[i][j][2] == 0) {
                    ans += resetBackGround;
                    ans += kongge;
                }
                else {
                    // ESC [ ; 4 8 ;
                    ans += changBackGround;

                    int shang, yu;

                    // R ;
                    string curR;
                    shang = myRGB[i][j][0], yu = 0;
                    if (shang == 0) {
                        curR = ten2sixteen('0');
                    }
                    else {
                        while (shang != 0) {  // 这样是倒序的
                            yu = shang % 10;
                            shang = shang / 10;
                            curR = ten2sixteen(yu + '0') + curR;  // 这样一下就正序了
                        }
                    }
                    ans += curR;
                    //ans += ten2sixteen(myRGB[i][j][0]);
                    ans += fenhao;

                    // G ;
                    string curG;
                    shang = myRGB[i][j][1], yu = 0;
                    if (shang == 0) {
                        curG = ten2sixteen('0');
                    }
                    else {
                        while (shang != 0) {
                            yu = shang % 10;
                            shang = shang / 10;
                            curG = ten2sixteen(yu + '0') + curG;
                        }
                    }
                    ans += curG;
                    ans += fenhao;

                    // B
                    string curB;
                    shang = myRGB[i][j][2], yu = 0;
                    if (shang == 0) {
                        curB = ten2sixteen('0');
                    }
                    else {
                        while (shang != 0) {
                            yu = shang % 10;
                            shang = shang / 10;
                            curB = ten2sixteen(yu + '0') + curB;
                        }
                    }
                    ans += curB;
                    //ans += fenhao; /* 不需要!!! B后边不需要分号!!!*/

                    // 添加 m
                    ans += zimum;

                    // 添加色块
                    ans += kongge;
                }

                //
                preR = myRGB[i][j][0];
                preG = myRGB[i][j][1];
                preB = myRGB[i][j][2];
            }
        }

        // 该行结束
        // 1. 还原成默认背景色, 使用重置 2. 修改preRGB 3. 添加换行符
        if (preR != 0 || preG != 0 || preB != 0) {
            ans += resetBackGround;
            preR = preG = preB = 0;
        }
        ans += huanhang;
    }

    cout<<ans;

    return 0;
}

代码挺长的,可以修改/删除一些地方(比如规划输出那一段中一长串字符的定义,可以从题目中就知道,就不用再转来转去了),优化一些地方(最后两个大循环应该可以并到一起),删除一些注释掉了的段落,但是懒得弄了。

参考文章

从0分到100分,全靠这篇文章中给出的测试数据。(自己懒了点,也没想到那两个方面)
CCF CSP 20190903 字符画 100分

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值