B3851 [GESP202306 四级] 图像压缩 题解

· · 题解

【题目大意】 先根据输入将输入的十六进制两两成对转换为十进制 0~255 之间的数,再取出现次数较多的前 16 个数作为标准 “ 灰阶 ” ,将其他的数根据与标准 “ 灰阶 ”作差的绝对值大小就近转换为对应 “ 灰阶 ” ,最后再将灰阶转换为 16 进制输出。

【解题思路】

  1. 模拟题,我们按照题目的要求进行模拟即可,首先将数据输入,并把 16 进 制转换为 10 进制。
  2. 接着我们找出出现次数最多的 16 种灰阶,并给它们编号为 0-F 。
  3. 然后遍历所有的灰阶,找出距离它们各自最近的 16 种灰阶之一。
  4. 先输出出现次数最多的 16 种灰阶,记得转换为 16 进制,再输出压缩后的图像,即所有的灰阶都输出距离它们各自最近的 16 种灰阶之一。

【考纲知识点】多层循环(二级),模拟法 ( 三级 ) ,函数的定义与调用(四级)

【参考程序】

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
int a[25][25];//保存输入数据
struct Node{//不同灰度的数量
    int hd;//灰度
    int sl;//数量
}c[300];
//十六进制转10进制
int toint(char c){
    if (c>='A'&&c<='F'){
        return c-'A'+10;
    }
    return c-'0';
}
//将10进制打印为16进制
void printHx(int x){
    char c;
    if (x>9){
        c='A'+x-10;
    }else{
        c=x+'0';
    }
    cout<<c;
}
//按出现的数量从大到小排序,数量相同,灰度小的排前边
bool cmp(Node x,Node y){
    if (x.sl==y.sl) return x.hd<y.hd;
    return x.sl>y.sl;
}
int main() {
    int n;
    cin>>n;
    string s;
    for (int i=1;i<=n;i++){
        cin>>s;
        int t;
        //16进制转换为10进制保存到数组中
        for (int j = 0; j < s.size(); j += 2) {
            t = toint(s[j]) * 16 + toint(s[j + 1]);
            a[i][j / 2 + 1] = t;
            c[t].sl++;  //标记灰度值为t出现的次数 
        }
    }
    for (int i=1;i<=255;i++){//初始化灰度值
        c[i].hd=i;
    }
    sort(c,c+256,cmp);//排序
    for (int i=0;i<16;i++){//打印排名前16
        printHx(c[i].hd/16);
        printHx(c[i].hd%16);
    }
    cout<<endl;
    int len=s.length()/2;
    for (int i=1;i<=n;i++){//找到每个像素点的最近值
        for (int j=1;j<=len;j++){
            int minn=256;
            int p=0;
            for (int k=0;k<=15;k++){
                if (abs(c[k].hd-a[i][j])<minn){
                    minn=abs(c[k].hd-a[i][j]);
                    p=k;  //记录编号 
                }
            }
            printHx(p);//打印与其最近的灰度值编号的16进制 
        }
        cout<<endl;
    }
    return 0;
}