CCF-GESP计算机学会等级考试2023年6月四级C++T2图像压缩

试题编号: 2023-06-11-04-C-02
试题名称:图像压缩
时间限制: 1.0s
内存限制: 128.0MB
【问题描述】
图像是由很多的像素点组成的。如果用 0 表示黑, 255 表示
白, 0 255 之间的值代表不同程度的灰色,则可以用一个字节表达
一个像素(取值范围为十进制 0-255 、十六进制 00-FF )。这样的像素
组成的图像,称为 256 级灰阶的灰度图像。
现在希望将 256 级灰阶的灰度图像压缩为 16 级灰阶,即每个
像素的取值范围为十进制 0-15 、十六进制 0-F 。压缩规则为:统计出
每种灰阶的数量,取数量最多的前 16 种灰阶(如某种灰阶的数量与另
外一种灰阶的数量相同,则以灰阶值从小到大为序),分别编号 0-F
(最多的编号为 0 ,以此类推)。其他灰阶转换到最近的 16 种灰阶之
一,将某个点灰阶数与 16 种灰阶种的一种相减,绝对值最小即为最
近,如果绝对值相等,则编号较小的灰阶更近。
【输入描述】
输入第 1 行为一个正整数 N ,表示接下来有 N 行数据组成一
256 级灰阶的灰度图像。约定 10≤N≤20
2 行开始的 N 行,每行为长度相等且为偶数的字符串,每
两个字符用十六进制表示一个像素。约定输入的灰度图像至少有 16
灰阶。约定每行最多 20 个像素。
【输出描述】
第一行输出压缩选定的 16 种灰阶的十六进制编码,共计 32
个字符。
第二行开始的 N 行,输出压缩后的图像,每个像素一位十六
进制数表示压缩后的灰阶值。 【样例输入 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 】 灰阶 AB CF FF 出现 14 次, 00 出现 9 次, CB 出现 9
次, 09 出现 7 次, AC 出现 6 次, 07 出现 5 次, 10 11 98 出现 4 次,
01 1B 67 76 FC 出现 3 次。

【解析】直接模拟,详见代码

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
int toint(char c){//十六进制转10进制
    if (c>='A'&&c<='F'){
        return c-'A'+10;
    }
    return c-'0';
}
int a[25][25];//保存输入数据
struct node{//不同灰度的数量
    int hd;//灰度
    int sl;//数量
}c[300];
void myprint(int x){//将10进制打印为16进制
    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;
        for (int j = 0; j < s.size(); j += 2) {//转换为10进制保存到数组中
            t = toint(s[j]) * 16 + toint(s[j + 1]);
            a[i][j / 2 + 1] = t;
            c[t].sl++;
        }
    }
    for (int i=1;i<=255;i++){//初始化灰度值
        c[i].hd=i;
    }
    sort(c,c+256,cmp);//排序
    for (int i=0;i<16;i++){//打印排名前16
        myprint(c[i].hd/16);
        myprint(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 cha=256;
            int p=0;
            for (int k=0;k<=15;k++){
                if (abs(c[k].hd-a[i][j])<cha){
                    cha=abs(c[k].hd-a[i][j]);
                    p=k;
                }
            }
            myprint(p);//打印
        }
        cout<<endl;
    }
    return 0;
}

 感谢之江学院石老师提供的更简练的代码:

#include<bits/stdc++.h>
using namespace std;
string s[23], p = "0123456789ABCDEF";
int n, his[256], cn, a[23][23], t[16];
vector<array<int, 2>>v;
int main()
{
	cin >> n;
	for(int i = 0; i < n; i++)
	{
		cin >> s[i];
		cn = s[i].size() / 2;
		for(int j = 0; j < cn; j++)
			his[a[i][j] = p.find(s[i][2*j])*16 + p.find(s[i][2*j+1])]++;
	}
	for(int i = 0; i < 256; i++)
		v.push_back({-his[i], i});
	sort(v.begin(), v.end());
	for(int i = 0; i < 16; i++)
		printf("%02X", v[i][1]);
	for(int i = 0; puts(""), i < n; i++)
		for(int j = 0; j < cn; j++)
		{
			for(int k = 0; k < 16; k++)
				t[k] = abs(v[k][1]-a[i][j]);
			printf("%X", min_element(t, t + 16) - t);
		}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长春高老师编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值