CCF-CSP 202212-3 JPEG编码

思路:本题采用模拟的思想按照题目中的步骤计算即可,分别写出三个步骤的方法,填充、量化、逆变换。而后根据T值分别调用不同的方法计算矩阵即可。

填充

填充矩阵时依次按对角线来填充。从左上角开始,不难观察出第偶数条对角线的填充方向为右上,第奇数条对角线的填充方向为左下。将整个矩阵按照最中间的对角线分为两部分,第一部分的每条对角线依次增长,第二部分依次减小。该方法代码如下:

void fill(vector>&M, vector nums) {
    int k = 0;
    for (int i = 0; i < 8; i++) { //填充左上部分
        if (i % 2 == 0) {  //第偶数个对角线
            for (int j = 0; j <= i; j++) {
                M[i - j][j] = nums[k++];
            }
        }
        else {  //第奇数个对角线
            for (int j = 0; j <= i; j++) {
                M[j][i - j] = nums[k++];
            }
        }
    }

    for (int i = 8; i < 15; i++) {  //填充右下部分
        if (i % 2 == 0) {
            for (int j = i - 7; j <= 7; j++) {
                M[i - j][j] = nums[k++];
            }
        }
        else {
            for (int j = i - 7; j <= 7; j++) {
                M[j][i - j] = nums[k++];
            }
        }
    }
}

解决填充时,我还使用了另外一种算法。使用一个变量dir来记录当前填充的方向是左下还是右上。依次遍历填充数组,将元素依次填入矩阵。但使用该算法进行填充时在本地运行可以通过,在CCF-CSP模拟时是零分。代码如下:

void fill(vector>& M, vector nums, int n) { //n为填充数组的元素个数
    int x = 0;
    int y = 0;
    int dir = 1;  //1为右上,0为左下
    for (int k = 0; k < n; k++) {
        if (x >= 0 && x < 8 && y >= 0 && y < 8) { //边界
            M[x][y] = nums[k];
        }
        if (dir == 0) {
            x++;
            y--;
        }
        else if (dir == 1) {
            x--;
            y++;
        }
        if (x < 0) {
            x = 0;
            dir = 0; //超出上边界则修改方向为左下
        }
        if (y < 0) {
            y = 0;
            dir = 1; //超出左边界则修改方向为右上
        }
    }
}
量化

该步骤较简单,将填充后的矩阵与量化矩阵逐项相称即可。

void qnentify(vector> Q, vector> &M) {
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            M[i][j] *= Q[i][j];
        }
    }
}
逆变换

该步骤主要是将题目中所给的公式转换为代码计算。本步骤要注意double和int数据类型的转换。应该新声明一个double类型的二维数组记录变换结果。代码如下:

void DCT(vector> M, vector> &newM) {
    double temp = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            
            //余弦逆变换
            for (int u = 0; u < 8; u++) {
                for (int v = 0; v < 8; v++) {
                    if (u == 0 && v == 0) {
                        newM[i][j] += (double)M[u][v] * cos(0) * cos(0) / 2.0;
                    }
                    else if (u == 0) {
                        newM[i][j] += (double)M[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                    else if (v == 0) {
                        newM[i][j] += (double)M[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                    else {
                        newM[i][j] += (double)M[u][v] * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                }
            }
            newM[i][j] /= 4.0; //逆变换结束


            newM[i][j] = round(newM[i][j] + 128); //逆转换结果 加128得到最终结果
            if (newM[i][j] > 255) {
                newM[i][j] = 255;
            }
            if (newM[i][j] < 0) {
                newM[i][j] = 0;
            }
        }
    }
}
完整代码
#include
#include
#include
using namespace std;

void fill(vector>&M, vector nums) {
    int k = 0;
    for (int i = 0; i < 8; i++) { //填充左上部分
        if (i % 2 == 0) {  //第偶数个对角线
            for (int j = 0; j <= i; j++) {
                M[i - j][j] = nums[k++];
            }
        }
        else {  //第奇数个对角线
            for (int j = 0; j <= i; j++) {
                M[j][i - j] = nums[k++];
            }
        }
    }

    for (int i = 8; i < 15; i++) {  //填充右下部分
        if (i % 2 == 0) {
            for (int j = i - 7; j <= 7; j++) {
                M[i - j][j] = nums[k++];
            }
        }
        else {
            for (int j = i - 7; j <= 7; j++) {
                M[j][i - j] = nums[k++];
            }
        }
    }
}
void qnentify(vector> Q, vector> &M) {
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            M[i][j] *= Q[i][j];
        }
    }
}
void DCT(vector> M, vector> &newM) {
    double temp = 0;
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            
            //余弦逆变换
            for (int u = 0; u < 8; u++) {
                for (int v = 0; v < 8; v++) {
                    if (u == 0 && v == 0) {
                        newM[i][j] += (double)M[u][v] * cos(0) * cos(0) / 2.0;
                    }
                    else if (u == 0) {
                        newM[i][j] += (double)M[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                    else if (v == 0) {
                        newM[i][j] += (double)M[u][v] * sqrt(0.5) * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                    else {
                        newM[i][j] += (double)M[u][v] * cos(acos(-1) * (i + 0.5) * double(u) / 8.0) * cos(acos(-1) * (j + 0.5) * v / 8.0);
                    }
                }
            }
            newM[i][j] /= 4.0; //逆变换结束


            newM[i][j] = round(newM[i][j] + 128); //逆转换结果 加128得到最终结果
            if (newM[i][j] > 255) {
                newM[i][j] = 255;
            }
            if (newM[i][j] < 0) {
                newM[i][j] = 0;
            }
        }
    }
}

int main() {
    int n;
    int T;
    vector> Q(8, vector(8, 0));
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            cin >> Q[i][j];
        }
    }
    cin >> n;
    cin >> T; 
    vector nums(64);
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
    }
    vector>M (8, vector(8, 0));
    vector>newM (8, vector(8, 0));

    if (T == 0) {
        fill(M, nums);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                cout << M[i][j] << " ";
            }
            cout << endl;
        }
    }
    else if (T == 1) {
        fill(M, nums);
        qnentify(Q, M);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                cout << M[i][j] << " ";
            }
            cout << endl;
        }
    }
    else if(T == 2) {
        fill(M, nums);
        qnentify(Q, M);
        DCT(M, newM);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                cout << newM[i][j] << " ";
            }
            cout << endl;
        }
    }
    return 0;
}

你可能感兴趣的:(CCF-CSP刷题记录,c++,算法,数据结构)