2022-12-3 JPEG 解码 大模拟 不需要任何优化手段 最简单的第三题
2022-12-3 JPEG 解码 大模拟 不需要任何优化手段 最简单的第三题
这题堪称是最简单的第三题,没有用到任何的优化手段,没有用到任何的特殊的数据结构,只需要按着题目来就好了。
思路
这题只要是看懂题目了就基本有思路,稍微有一个难点就是模拟那个z字形的填充。
模拟z字形的填充有两种方式,第一种就是找到z字形填充的数学映射,就是第i个数该插在 第u行第v列的映射关系,这种是比较困难的,需要有较强的数学推导和归纳总结能力,我一开始想这样处理但是发现自己找不到规律。
第二种就是直接模拟z字形填充的过程,判断好什么时候右移,什么时候下移,等等的,然后在循环里移动就好了。
具体实现就是这个函数,这种思路非常的通俗易懂
如果是上半个矩阵
- 如果这一行(斜着的行)往右上角移动那么这行结束时要右移
- 如果这一行(斜着的行)往左下角移动那么这行结束时就要下移
如果是下半个矩阵
- 大家可以自己想一想
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; } }
但是其中还是有一点坑的地方。
遇到的问题
- 下半个矩阵的填充规则和上半个矩阵并不相同,一开始以为相同就搞错了,和上半个矩阵的规则整相反,如果是往右上角移动那么最后要向下移动。
没有修改之前
修改之后
- 在过了第一个测试点之后就写了量化的代码,但是发现还是20分,然后才发现是我的量化矩阵和数据的矩阵的ij对不上,量化矩阵式从1开始的而数据矩阵是从0开始的,修改之后就好了。
修改之前
修改之后
- 在完成了第二个测试点后,写了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)给搞错了
- 最后补上了取整的代码就是还是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;
}