【CSP】2022-12-3 JPEG 解码 大模拟 不需要任何优化手段 最简单的第三题

本文讲述了如何进行JPEG解码中的一种简单模拟,无需使用优化手段,主要涉及Z字形填充算法的实现,包括上半部分和下半部分矩阵的插入,以及DCT转换和量化过程中的注意事项,强调了仔细阅读题目和检查细节的重要性。
摘要由CSDN通过智能技术生成

2022-12-3 JPEG 解码 大模拟 不需要任何优化手段 最简单的第三题

2022-12-3 JPEG 解码 大模拟 不需要任何优化手段 最简单的第三题

这题堪称是最简单的第三题,没有用到任何的优化手段,没有用到任何的特殊的数据结构,只需要按着题目来就好了。

思路

这题只要是看懂题目了就基本有思路,稍微有一个难点就是模拟那个z字形的填充。

模拟z字形的填充有两种方式,第一种就是找到z字形填充的数学映射,就是第i个数该插在 第u行第v列的映射关系,这种是比较困难的,需要有较强的数学推导和归纳总结能力,我一开始想这样处理但是发现自己找不到规律。

第二种就是直接模拟z字形填充的过程,判断好什么时候右移,什么时候下移,等等的,然后在循环里移动就好了。

具体实现就是这个函数,这种思路非常的通俗易懂

在这里插入图片描述

  1. 如果是上半个矩阵

    1. 如果这一行(斜着的行)往右上角移动那么这行结束时要右移
    2. 如果这一行(斜着的行)往左下角移动那么这行结束时就要下移
  2. 如果是下半个矩阵

    1. 大家可以自己想一想

void insertMatrix()
{
    // 首先插入上半个矩阵
    int x = 0, y = 0, moveflag = 1; // moveflag如果是右移则是1 如果是下移则是0
    for (int i = 1; i <= 8; i++)//上半个矩阵一共有8行(斜着的行)
    {
        for (int j = 1; j <= i; j++)//每一行的数量是1 2 3 4…………8
        {
            m[x][y] = data1[top++];

            if (top == n) // 已经把所有数据都插入了
            {
                return;
            }
            if (j != i && moveflag == 1)
            {
                x--;
                y++;
            }
            else if (j != i && moveflag == 0)
            {
                x++;
                y--;
            }
        }
        if (moveflag == 1) // 如果是右移
        {
            y++;
        }
        else if (moveflag == 0)
        {
            x++;
        }
        moveflag = !moveflag;
    }

    moveflag = 0;
    x = 7, y = 1;
    // 然后插入下半个矩阵
    for (int i = 7; i >= 1; i--)//下半个矩阵一共有7行(斜着的行)
    {
        for (int j = 1; j <= i; j++)//每一行的数量是7 6 5 …… 1
        {
            m[x][y] = data1[top++];
            if (top == n) // 已经把所有数据都插入了
            {
                return;
            }
            if (j != i && moveflag == 1)
            {
                x++;
                y--;
            }
            else if (j != i && moveflag == 0)
            {
                x--;
                y++;
            }
        }
        if (moveflag == 1) // 如果是右移
        {
            y++;
        }
        else if (moveflag == 0) // 如果是下移
        {
            x++;
        }
        moveflag = !moveflag;
    }
}

但是其中还是有一点坑的地方。

遇到的问题

  1. 下半个矩阵的填充规则和上半个矩阵并不相同,一开始以为相同就搞错了,和上半个矩阵的规则整相反,如果是往右上角移动那么最后要向下移动。

没有修改之前

在这里插入图片描述

修改之后
在这里插入图片描述

  1. 在过了第一个测试点之后就写了量化的代码,但是发现还是20分,然后才发现是我的量化矩阵和数据的矩阵的ij对不上,量化矩阵式从1开始的而数据矩阵是从0开始的,修改之后就好了。

修改之前

在这里插入图片描述

修改之后

在这里插入图片描述

  1. 在完成了第二个测试点后,写了dct变化的代码,然后输出中间数据发现,和题目给的经过dct变化后的结果不一样,后来发现是公式写错了

这里的 DctConvert里的数据写错了

double a1 = i == 0 ? sqrt(0.5) : 1, a2 = j == 0 ? sqrt(0.5) : 1;

我写成了

double a1 = x == 0 ? sqrt(0.5) : 1, a2 = y == 0 ? sqrt(0.5) : 1;

正确的函数

double DctConvert(int x, int y)
{
    double sum = 0;
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            double a1 = i == 0 ? sqrt(0.5) : 1, a2 = j == 0 ? sqrt(0.5) : 1;
            sum += a1 * a2 * m[i][j] * cos(pi8 * (x + 0.5) * i) * cos(pi8 * (y + 0.5) * j);
        }
    }
    return sum / 4;
}

也就是题目中的 α ( u )     α ( v ) \alpha(u) \ \ \ \alpha(v) α(u)   α(v)给搞错了

  1. 最后补上了取整的代码就是还是40分

这里学会了一个四舍五入为整数的函数

round()

其实我们也可以手写round()函数

就是

int round(double x)
{
    return (int)x+0.5
}

如果我们要求其他位的四舍五入,可以先乘个10,然后四舍五入为整数,然后再除以个10

这里遇到的问题就是:忽略了题目的一个规则

如果得到的整数大于 255,则取 255;如果得到的整数小于 0,则取 0。

补上这个条件就100分了

在这里插入图片描述

感悟

这题确实很简单,主要是题目限制了一个特定的数据范围,然后直接暴力就可以求解。

遇到问题后应该再仔细读一读题目,将题目的条件都列下来,然后并且把自己的推论也都列出来,看看哪些推论是自己乱想的,并且检查还有没有漏掉的。

如果一直满分不了,那么一定是还有问题,有可能是实现的细节问题,也有可能是思路的问题(没有想全面,只是按着给的样例的数据了),还有可能是读题问题(有地方没有读到被忽略了)。

完整代码

#include <bits/stdc++.h>
using namespace std;
const double pi8 = acos(-1) / 8;
int n, data1[65], top;
int q[8][8], m[8][8]; // 量化矩阵和数据矩阵
int T;
void insertMatrix()
{
    // 首先插入上半个矩阵
    int x = 0, y = 0, moveflag = 1; // moveflag如果是右移 则是1 如果是下移则是0
    for (int i = 1; i <= 8; i++)
    {
        for (int j = 1; j <= i; j++)
        {
            m[x][y] = data1[top++];

            if (top == n) // 已经把所有数据都插入了
            {
                return;
            }
            if (j != i && moveflag == 1)
            {
                x--;
                y++;
            }
            else if (j != i && moveflag == 0)
            {
                x++;
                y--;
            }
        }
        if (moveflag == 1) // 如果是右移
        {
            y++;
        }
        else if (moveflag == 0)
        {
            x++;
        }
        moveflag = !moveflag;
    }

    moveflag = 0;
    x = 7, y = 1;
    // 然后插入下半个矩阵
    for (int i = 7; i >= 1; i--)
    {
        for (int j = 1; j <= i; j++)
        {
            m[x][y] = data1[top++];
            if (top == n) // 已经把所有数据都插入了
            {
                return;
            }
            if (j != i && moveflag == 1)
            {
                x++;
                y--;
            }
            else if (j != i && moveflag == 0)
            {
                x--;
                y++;
            }
        }
        if (moveflag == 1) // 如果是右移
        {
            y++;
        }
        else if (moveflag == 0) // 如果是下移
        {
            x++;
        }
        moveflag = !moveflag;
    }
}
void multipleMatrix()
{
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            m[i][j] *= q[i][j];
        }
    }
}
double DctConvert(int x, int y)
{
    double sum = 0;
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            double a1 = i == 0 ? sqrt(0.5) : 1, a2 = j == 0 ? sqrt(0.5) : 1;
            sum += a1 * a2 * m[i][j] * cos(pi8 * (x + 0.5) * i) * cos(pi8 * (y + 0.5) * j);
        }
    }
    return sum / 4;
}
void addAll(double matr[8][8])
{

    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            m[i][j] = (int)(matr[i][j] + 128 + 0.5);
            if (m[i][j] > 255)
            {
                m[i][j] = 255;
            }
            else if (m[i][j] < 0)
            {
                m[i][j] = 0;
            }
        }
    }
}
void show(int martrix[8][8])
{
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            cout << martrix[i][j] << ' ';
        }
        cout << endl;
    }
}
int main()
{
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            cin >> q[i][j];
        }
    }
    cin >> n;
    cin >> T;
    for (int i = 0; i < n; i++)
    {
        cin >> data1[i];
    }
    if (T == 0)
    {
        insertMatrix();
    }
    else if (T == 1)
    {
        insertMatrix();
        multipleMatrix();
    }
    else if (T == 2)
    {
        insertMatrix();
        multipleMatrix();
        double m2[8][8];
        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 8; j++)
            {
                m2[i][j] = DctConvert(i, j);
            }
        }
        addAll(m2);
    }
    show(m);
    return 0;
}

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值