gesp(C++四级)(4)洛谷:B3851:[GESP202306 四级] 图像压缩
题目描述
图像是由很多的像素点组成的。如果用
0
0
0 表示黑,
255
255
255 表示白,
0
0
0 和
255
255
255 之间的值代表不同程度的灰色,则可以用一个字节表达一个像素(取值范围为十进制 0-255
、十六进制 00-FF
)。这样的像素组成的图像,称为
256
256
256 级灰阶的灰度图像。
现在希望将
256
256
256 级灰阶的灰度图像压缩为
16
16
16 级灰阶,即每个像素的取值范围为十进制 0-15
、十六进制 0-F
。压缩规则为:统计出每种灰阶的数量,取数量最多的前
16
16
16 种灰阶(如某种灰阶的数量与另外一种灰阶的数量相同,则以灰阶值从小到大为序),分别编号 0-F
(最多的编号为 0
,以此类推)。其他灰阶转换到最近的
16
16
16 种灰阶之一,将某个点的灰阶值(灰度,而非次数)与
16
16
16 种灰阶中的一种相减,绝对值最小即为最近,如果绝对值相等,则编号较小的灰阶更近。
输入格式
输入第 1 1 1 行为一个正整数 n ( 10 ≤ n ≤ 20 ) n(10\le n \le 20) n(10≤n≤20),表示接下来有 n n n 行数据组成一副 256 256 256 级灰阶的灰度图像。
第 2 2 2 行开始的 n n n 行,每行为长度相等且为偶数的字符串,每两个字符用十六进制表示一个像素。约定输入的灰度图像至少有 16 16 16 种灰阶。约定每行最多 20 20 20 个像素。
输出格式
第一行输出压缩选定的 16 16 16 种灰阶的十六进制编码,共计 32 32 32 个字符。
第二行开始的 n n n 行,输出压缩后的图像,每个像素一位十六进制数表示压缩后的灰阶值。
样例 #1
样例输入 #1
10
00FFCFAB00FFAC09071B5CCFAB76
00AFCBAB11FFAB09981D34CFAF56
01BFCEAB00FFAC0907F25FCFBA65
10FBCBAB11FFAB09981DF4CFCA67
00FFCBFB00FFAC0907A25CCFFC76
00FFCBAB1CFFCB09FC1AC4CFCF67
01FCCBAB00FFAC0F071A54CFBA65
10EFCBAB11FFAB09981B34CFCF67
01FFCBAB00FFAC0F071054CFAC76
1000CBAB11FFAB0A981B84CFCF66
样例输出 #1
ABCFFF00CB09AC07101198011B6776FC
321032657CD10E
36409205ACC16D
B41032657FD16D
8F409205ACF14D
324F326570D1FE
3240C245FC411D
BF4032687CD16D
8F409205ACC11D
B240326878D16E
83409205ACE11D
提示
【样例 1 1 1 解释】
灰阶 AB
、CF
和 FF
出现
14
14
14 次,00
出现
10
10
10 次,CB
出现
9
9
9 次,09
出现
7
7
7 次,AC
出现
6
6
6 次,07
出现
5
5
5 次,10
、11
和 98
出现
4
4
4 次,01
、1B
、67
、76
和 FC
出现
3
3
3 次。
AC代码(100分)
#include<bits/stdc++.h>
using namespace std;
int n,a[30][30];//a数组用于保存转换后的输入数据
string s;
//创建结构体:10进制的灰度及其出现次数
struct node{
int grey;//灰度
int cnt;//出现次数
}p[260];
//十六进制字符转10进制整数
int to10(char c){
int ans;
if(c>='0' && c<='9') ans=c-'0';
else ans=c-'A'+10;
return ans;
}
//排序规则函数
bool cmp(node x,node y){
if(x.cnt!=y.cnt) return x.cnt>y.cnt;//优先按灰度出现的次数降序
else return x.grey<y.grey;//其次按灰度编号升序
}
//10进制整数打印为16进制
void print16(int x){
char c;
if(x>9) c='A'+x-10;
else c='0'+x;
cout<<c;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){//n行
cin>>s;//输入每行的字符串
//两个字符一组,将16进制转换位10进制保存到数组中
int x;
for(int j=0;j<s.size();j+=2){
x=to10(s[j])*16+to10(s[j+1]);//调用字符转十进制函数
a[i][j/2+1]=x;//存到a数组中
p[x].cnt++; //统计灰度出现的次数
}
}
//初始化灰度
for(int i=0;i<256;i++){
p[i].grey=i;
}
//p数组排序
sort(p,p+256,cmp);
//输出灰度排名前16:需将10进制数字转换回16进制字符
for(int i=0;i<16;i++){
print16(p[i].grey/16);//打印两位十六进制中的第1位
print16(p[i].grey%16);//打印两位十六进制中的第2位
}
cout<<endl;
//输出压缩后的图像
int len=s.size()/2;
for(int i=1;i<=n;i++){
for(int j=1;j<=len;j++){
int minc=256;//存:最小差绝对值
int b=0;//存:最接近的灰度编号
for(int k=0;k<=15;k++){
if(abs(p[k].grey-a[i][j])<minc){
minc=abs(p[k].grey-a[i][j]);
b=k;//更新编号
}
}
//打印找到的与其最近的灰度编号的16进制
print16(b);
}
cout<<endl;
}
return 0;
}
文末彩蛋:
点击王老师青少年编程主页有更多精彩内容