#include <iostream>
#include <fstream>
#include <vector>
#include <stack>
#include <random>
#include <string>
#include <algorithm>
#include <deque>
#include<cmath>
#include <map>
#include <cstdint>
using namespace std;
struct Pix
{
uint8_t v;
int cnt;
Pix() : v(0), cnt(0) {}
bool operator < (const Pix& p) const
{
if (cnt != p.cnt)
return cnt > p.cnt;
return v < p.v;
}
};
uint8_t bit[20][40];
uint8_t cacle(uint8_t pix, const vector<Pix> &v)
{
uint8_t retv=0xff;
uint8_t ret =0xff;
uint8_t minv;
for (uint8_t i = 0; i < 16; i++)
{
if (ret > abs(pix - v[i].v))
{
ret = abs(pix - v[i].v);
minv = i;
}
}
return minv;
}
int cnt[256];
int main()
{
int n;
cin >> n;
string str;
int l;
for (int i = 0; i < n; i++)
{
cin >> str;
l = str.length();
for (int j = 0; j < l; j += 2)
{
char tmp[3] = { 0 };
tmp[0] = str[j];
tmp[1] = str[j + 1];
sscanf(tmp, "%X", &bit[i][j / 2]);
}
}
vector<Pix> v;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < l / 2; j++)
{
cnt[bit[i][j]]++;
}
}
for (int i = 0; i <= 255; i++)
{
if (cnt[i] > 0)
{
Pix p;
p.v = i;
p.cnt = cnt[i];
v.emplace_back(p);
}
}
sort(v.begin(), v.end());
for (int i = 0; i < 16; i++)
{
printf("%02X", v[i].v);
}
printf("\n");
for (int i = 0; i < n; i++)
{
for (int j = 0; j < l / 2; j++)
{
printf("%X", cacle(bit[i][j],v));
}
printf("\n");
}
return 0;
}
利用好C的占位符,这题能省去很多功夫。 遇到的问题: 1.设计存储基本数据结构,要既方便接收也要方便处理。很明显题目是希望用字符串的方式去处理,但是我很懒,所以决定用整数形式去存后期处理会轻松不少,所以开了一个uint8_t 的二维数组去存图像的像素值,无论后期题目要统计或者位运算放马过来。由于题目后期需要用到复合规则的排序,所以使用了结构体来用了处理前16个字节的排序,写好operator,再复杂的排序规则都不怕。%o,%X简直是神器。 2.处理接收,由于值知道行,不知道列,所以接收过程用了一下string类过渡,好在长度一样,那么接收好之后两个字符一取,得到两位一个十六进制值,在利用sscanf,配合%X占位符成功接收近uint8_t 整数变量中(不关心十进制值是多少,就抽象的理解成一个字节就行) 3.开始烦人的模拟,先统计每种像素出行的频次,这个非常简单,一个字节的范围是0到255(这个都不知道就别考四级了)所以开一个256的一维数字下标对位统计一下就行了,再开销256趟循环,把统计非0的像素值提取出来,存入结构体数据:像素值是什么,一共几个(这里有个技巧,如果是vector容器,采用emplace_back要比push_back快,快在少一次构造的过程,但是只有c++11才支持),用于排序,指定排序规则后调用sort一下,题目解决了40%,那么第一行输出就能解决但是主义确保十六进制是两位所以要注意占位符采用%02X输出。然后就是统计,简单的搜索,在前16个像素点中找与当前像素点绝对值最小的,由于题目前面排序规则的影响,如果绝对值一样则取值最小,将找到的下标,用%X输出(0-16作为16进制当然只有一位),至此解题完成