1 条题解

  • 0
    @ 2025-4-9 20:48:24

    解题思路

    程序的主要功能是解析并输出一个由 ASCII 字符构成的表格。输入的表格以特定的 ASCII 字符绘制,程序会处理这些输入,计算各列的宽度,最终输出格式规范、排版整齐的表格。

    详细题解

    1. 头文件与类型定义

    #include<iostream>
    #include<stdio.h>
    #include<vector>
    #include<string>
    #include<sstream>
    #include<string.h>
    using namespace std;
    typedef basic_string<unsigned char> ustring;
    
    • 引入了一系列标准库的头文件,这些头文件涵盖了输入输出、字符串处理、向量操作等功能。
    • 定义了 ustring 类型,它本质上是 basic_string<unsigned char> 的别名,用于处理无符号字符类型的字符串。

    2. 表格边界字符数组

    unsigned char ccc[]={
        179, 196, // '│' '─'
        218, 194, 191, // '┌' '┬' '┐'
        195, 197, 180, // '├' '┼' '┤'
        192, 193, 217, // '└' '┴' '┘'
    };
    
    • 该数组存储了用于绘制表格边界的 ASCII 字符的编码。借助这些字符,程序能够绘制出规范的表格边框。

    3. 全局变量与辅助函数

    int col;
    unsigned char line[300];
    inline int ustrlen(unsigned char *s){
        int len = 0;
        while(s[len]!=0) len++;
        return len;
    }
    
    • col:用于记录表格的列数。
    • line:用于存储每行输入的字符。
    • ustrlen:这是一个内联函数,其作用是计算无符号字符数组的长度。

    4. 表格数据结构

    vector<vector<vector<unsigned char *> > > table;
    
    • table 是一个三维向量,其用途是存储表格中的数据。最外层向量代表行,中间层向量代表列,内层向量代表每个单元格可能包含的多行文本。

    5. 去除首尾空格函数

    unsigned char* trim(unsigned char* token){
        int len;
        for(len=0;token[len]!=0;len++){}
        int l=0,r=len-1;
        while(l<len && token[l]==' ') l++;
        while(r>=0 && token[r]==' ') r--;
        if(l>r) {
            unsigned char *ret = (unsigned char *)malloc(1*sizeof(unsigned char));
            ret[0] = 0;
            return ret;
        }
        unsigned char *ret = (unsigned char*)malloc((r-l+2)*sizeof(unsigned char));
        for(int i=0;i<=r-l;i++)
            ret[i] = token[l+i];
        ret[r-l+1] = 0;
        return ret;
    }
    
    • trim 函数的功能是去除无符号字符数组首尾的空格。若去除空格后数组为空,就返回一个空字符串;否则,返回去除空格后的新字符串。

    6. 打印单元格函数

    inline void print_cell(int i,int j,int k,int w){
        if(table[i][j].size()>k){
            cout<<" ";
            int len = ustrlen(table[i][j][k]);
            for(int l=0;l<len;l++) cout<<table[i][j][k][l];
            w-=len+1;
        }
        for(int l=0;l<w;l++)
            cout<<" ";
        return;
    }
    
    • print_cell 函数用于打印表格中的单元格。若单元格存在数据,就先输出一个空格,接着输出单元格内容,最后用空格填充剩余的宽度。

    7. 主函数流程

    7.1 计算列数
    while(cin>>std::noskipws>>c,c!=10){
        if(c==194) col++;
    }
    col+=1;
    
    • 读取输入的第一行,统计字符 194(即 )的数量,进而确定表格的列数。
    7.2 解析表格数据
    vector<vector<unsigned char*> > row;
    while(cin>>std::noskipws>>c){
        line[0] = c;
        int lc = 0;
        int sz = 1;
        while(cin>>std::noskipws>>c) {
            if(c==10) break;
            line[sz++] = c;
        }
        bool bad = false;
        for(int i=0;i<sz;i++)
            if(line[i]==196) {
                bad = true;
                break;
            }
        if(bad) {
            table.push_back(row);
            row.clear();
        }else{
            unsigned char token[300];
            int t_sz=0;
            int cnt = 0;
            for(int i=1;i<sz;i++){
                if(line[i]==179){
                    if(cnt==row.size()) row.push_back(vector<unsigned char*>());
                    token[t_sz] = 0;
                    row[cnt].push_back(trim(token));
                    t_sz = 0;
                    cnt++;
                }else token[t_sz++]=line[i];
            }
        }
    }
    
    • 逐行读取输入,若某行包含字符 196(即 ),则表明这是表格的分隔行,将当前行的数据添加到 table 中,并清空 row
    • 若不是分隔行,就按字符 179(即 )分割单元格,去除单元格内容的首尾空格后添加到 row 中。
    7.3 计算各列宽度
    vector<int> width(col,0);
    for(int i=0;i<table.size();i++)
        for(int j=0;j<table[i].size();j++)
            for(int k=0;k<table[i][j].size();k++){
                width[j]=max(width[j],ustrlen(table[i][j][k])+2);
            }
    
    • 遍历表格中的所有单元格,计算每列所需的最大宽度,宽度计算时会考虑单元格内容长度加上两侧的空格。
    7.4 输出表格
    // 输出表头行
    cout<<ccc[2];
    for(int i=0;i<col;i++)
    {
        for(int j=0;j<width[i];j++)
            cout<<ccc[1];
        if(i==col-1)cout<<ccc[4]<<endl;
        else cout<<ccc[3];
    }
    for(int i=0;i<table.size();i++){
        int ln = 0;
        for(int j=0;j<table[i].size();j++)
            ln = max(ln,(int)table[i][j].size());
        for(int l=0;l<ln;l++){
            cout<<ccc[0];
            for(int j=0;j<table[i].size();j++){
                print_cell(i,j,l,width[j]);
                cout<<ccc[0];
            }
            cout<<endl;
        }
        if(i!=table.size()-1){
            cout<<ccc[5];
            for(int j=0;j<col;j++)
            {
                for(int k=0;k<width[j];k++)
                    cout<<ccc[1];
                if(j==col-1)cout<<ccc[7]<<endl;
                else cout<<ccc[6];
            }
        }
    }
    // 输出表尾行
    cout<<ccc[8];
    for(int i=0;i<col;i++)
    {
        for(int j=0;j<width[i];j++)
            cout<<ccc[1];
        if(i==col-1)cout<<ccc[10];
        else cout<<ccc[9];
    }
    
    • 输出表头行,使用 ccc 数组中的字符绘制表格的上边框。
    • 逐行输出表格内容,若单元格有多行文本,则逐行输出。
    • 若不是最后一行,输出中间的分隔行。
    • 输出表尾行,绘制表格的下边框。

    复杂度分析

    • 时间复杂度O(n×m×k)O(n \times m \times k),这里的 nn 为行数,mm 为列数,kk 为每个单元格的平均行数。
    • 空间复杂度O(n×m×k)O(n \times m \times k),主要用于存储表格数据。
    #include<stdio.h>
    #include<vector>
    #include<string>
    #include<sstream>
    #include<string.h>
    using namespace std;
    typedef basic_string<unsigned char> ustring;
    //if contain '─' not a text line
    unsigned char ccc[]={
        179, 196, // '│' '─'
        218, 194, 191, // '┌' '┬' '┐'
        195, 197, 180, // '├' '┼' '┤'
        192, 193, 217, // '└' '┴' '┘'
    };
    
    
    int col;
    unsigned char line[300];
    inline int ustrlen(unsigned char *s){
        int len = 0;
        while(s[len]!=0) len++;
        return len;
    }
    vector<vector<vector<unsigned char *> > > table;
    unsigned char* trim(unsigned char* token){
        int len;
        for(len=0;token[len]!=0;len++){}
        int l=0,r=len-1;
        while(l<len && token[l]==' ') l++;
        while(r>=0 && token[r]==' ') r--;
        if(l>r) {
            unsigned char *ret = (unsigned char *)malloc(1*sizeof(unsigned char));
            ret[0] = 0;
            return ret;
        }
        unsigned char *ret = (unsigned char*)malloc((r-1+2)*sizeof(unsigned char));
        for(int i=0;i<=r-1+1;i++)
            ret[i] = token[l+i];
        ret[r-l+1] = 0;
        return ret;
    }
    inline void print_cell(int i,int j,int k,int w){
        if(table[i][j].size()>k){
            cout<<" ";
            int len = ustrlen(table[i][j][k]);
            for(int l=0;l<len;l++) cout<<table[i][j][k][l];
            w-=len+1;
        }
        for(int l=0;l<w;l++)
            cout<<" ";
        return;
    }
    int main()
    {
        unsigned char c;
        col = 0;
        while(cin>>std::noskipws>>c,c!=10){
            if(c==194) col++;
        }
        col+=1;
        vector<vector<unsigned char*> > row;
        while(cin>>std::noskipws>>c){
            line[0] = c;
            int lc = 0;
            int sz = 1;
            while(cin>>std::noskipws>>c) {
                if(c==10) break;
                line[sz++] = c;
            }
            bool bad = false;
            for(int i=0;i<sz;i++)
                if(line[i]==196) {
                    bad = true;
                    break;
                }
            if(bad) {
                table.push_back(row);
                row.clear();
            }else{
                unsigned char token[300];
                int t_sz=0;
                int cnt = 0;
                for(int i=1;i<sz;i++){
                    if(line[i]==179){
                        if(cnt==row.size()) row.push_back(vector<unsigned char*>());
                        token[t_sz] = 0;
                        row[cnt].push_back(trim(token));
                        t_sz = 0;
                        cnt++;
                    }else token[t_sz++]=line[i];
                }
            }
        }
        //calculate the width
        vector<int> width(col,0);
        //ustreln+2 
        for(int i=0;i<table.size();i++)
            for(int j=0;j<table[i].size();j++)
                for(int k=0;k<table[i][j].size();k++){
                    width[j]=max(width[j],ustrlen(table[i][j][k])+2);
                }
        //for(int i=0;i<col;i++)
        //    cout<<width[i]<<endl;
        
        
        //begin to print
        
        //header line
        cout<<ccc[2];
        for(int i=0;i<col;i++)
        {
            for(int j=0;j<width[i];j++)
                cout<<ccc[1];
            if(i==col-1)cout<<ccc[4]<<endl;
            else cout<<ccc[3];
        }
        for(int i=0;i<table.size();i++){
            //how many line this row need
            int ln = 0;
            for(int j=0;j<table[i].size();j++)
                ln = max(ln,(int)table[i][j].size());
            for(int l=0;l<ln;l++){
                cout<<ccc[0];
                for(int j=0;j<table[i].size();j++){
                    print_cell(i,j,l,width[j]);
                    cout<<ccc[0];
                }
                cout<<endl;
            }
            if(i!=table.size()-1){
                //print middle line  5 6 7
                cout<<ccc[5];
                for(int j=0;j<col;j++)
                {
                    for(int k=0;k<width[j];k++)
                        cout<<ccc[1];
                    if(j==col-1)cout<<ccc[7]<<endl;
                    else cout<<ccc[6];
                }
            }
        }
        
        cout<<ccc[8];
        for(int i=0;i<col;i++)
        {
            for(int j=0;j<width[i];j++)
                cout<<ccc[1];
            if(i==col-1)cout<<ccc[10];
            else cout<<ccc[9];
        }
        return 0;
    }
    
    • 1

    信息

    ID
    442
    时间
    1000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    7
    已通过
    1
    上传者