B3851 [GESP202306 四级] 图像压缩 题解
【题目大意】 先根据输入将输入的十六进制两两成对转换为十进制 0~255 之间的数,再取出现次数较多的前 16 个数作为标准 “ 灰阶 ” ,将其他的数根据与标准 “ 灰阶 ”作差的绝对值大小就近转换为对应 “ 灰阶 ” ,最后再将灰阶转换为 16 进制输出。
【解题思路】
- 模拟题,我们按照题目的要求进行模拟即可,首先将数据输入,并把 16 进 制转换为 10 进制。
- 接着我们找出出现次数最多的 16 种灰阶,并给它们编号为 0-F 。
- 然后遍历所有的灰阶,找出距离它们各自最近的 16 种灰阶之一。
- 先输出出现次数最多的 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;
}