思路:本题采用模拟的思想按照题目中的步骤计算即可,分别写出三个步骤的方法,填充、量化、逆变换。而后根据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;
}