#include using namespace std; const int k_Cnt_Colors = 16; const int k_H_Max = 512; const int k_W_Max = 512; const int k_Inf_Int = 1e9; const long long k_Inf_Long_Long = 1e18; const int k_Iterations = 10000; mt19937 rng(7); typedef array Color; typedef vector Row_Image; typedef vector Image; typedef vector Row_Image_Compressed; typedef vector Image_Compressed; typedef array Color_Palette; int get_difference_colors(const Color &a, const Color &b){ int ans = 0; ans += (int)(a[0] - b[0]) * (int)(a[0] - b[0]); ans += (int)(a[1] - b[1]) * (int)(a[1] - b[1]); ans += (int)(a[2] - b[2]) * (int)(a[2] - b[2]); return ans; } clock_t timer = clock(); inline float left_time(){ return (((float)clock() - (float)timer) / (float)CLOCKS_PER_SEC); } short get_closest_palette_color(const Color &color, const Color_Palette &palette){ short best_color_idx; int best_color_diff = k_Inf_Int; for(short color_idx = 0; color_idx < k_Cnt_Colors; ++color_idx){ int color_diff = get_difference_colors(color, palette[color_idx]); if(color_diff < best_color_diff){ best_color_idx = color_idx; best_color_diff = color_diff; } } return best_color_idx; } void get_best_image(Image_Compressed &best_image, const short &h, const short &w, const Color_Palette &palette, const Image &image){ for(short i = 0; i < h; ++i) for(short j = 0; j < w; ++j) best_image[i][j] = get_closest_palette_color(image[i][j], palette); } void get_best_dithered_image(Image_Compressed &best_image, const short &h, const short &w, const Color_Palette &palette, const Image &image){ static Image copy_image; copy_image = image; for(short j = 0; j < w; ++j){ for(short i = 0; i < h; ++i){ short new_color_idx = get_closest_palette_color(copy_image[i][j], palette); best_image[i][j] = new_color_idx; Color quant_error{0, 0, 0}; for(short k = 0; k < 3; ++k) quant_error[k] = image[i][j][k] - palette[new_color_idx][k]; for(short k = 0; k < 3; ++k){ if(i != h - 1) copy_image[i + 1][j ][k] += quant_error[k] * 7 / 16; if(i != 0 && j != w - 1) copy_image[i - 1][j + 1][k] += quant_error[k] * 3 / 16; if(j != w - 1) copy_image[i ][j + 1][k] += quant_error[k] * 5 / 16; if(i != h - 1 && j != w - 1) copy_image[i + 1][j + 1][k] += quant_error[k] * 1 / 16; } } } } void get_blurred_image(Image &best_image, const short &h, const short &w, const Color_Palette &palette, Image_Compressed &image){ for(short i = 0; i < h; ++i){ for(short j = 0; j < w; ++j){ array add{0, 0, 0}; short cnt = 4; for(int k = 0; k < 3; ++k) add[k] = cnt * palette[image[i][j]][k]; vector> adj{array{i + 1, j, 1}, array{i - 1, j, 1}, array{i, j + 1, 1}, array{i, j - 1, 1}}; for(const auto &to: adj){ if(to[0] < 0 || to[0] >= h || to[1] < 0 || to[1] >= w) continue; for(int i = 0; i < 3; ++i) add[i] += palette[image[to[0]][to[1]]][i] * to[2]; cnt += to[2]; } for(short k = 0; k < 3; ++k){ if(add[k] % cnt >= cnt / 2) best_image[i][j][k] = add[k] / cnt + 1; else best_image[i][j][k] = add[k] / cnt; } } } } long long get_ans_for_image(const Image_Compressed& new_image, const Color_Palette &palette, const short &h, const short &w, const Image &original_image){ long long ans = 0; for(short i = 0; i < h; ++i) for(short j = 0; j < w; ++j) ans += get_difference_colors(palette[new_image[i][j]], original_image[i][j]); return ans; } long long get_ans_for_image(const Image& new_image, const short &h, const short &w, const Image &original_image){ long long ans = 0; for(short i = 0; i < h; ++i) for(short j = 0; j < w; ++j) ans += get_difference_colors(new_image[i][j], original_image[i][j]); return ans; } void get_new_random_palette(Color_Palette &palette, const Image &image, uniform_int_distribution<> &dis_h, uniform_int_distribution <> &dis_w){ int cnt_it = k_Iterations; for(short i = 0; i < k_Cnt_Colors && cnt_it > 0; ++i, --cnt_it){ palette[i] = image[dis_h(rng)][dis_w(rng)]; bool ok = true; for(int j = 0; j < i; ++j){ if(palette[i] == palette[j]){ ok = false; break; } } if(!ok) --i; } } void get_new_palette_by_changing_best(Color_Palette &palette, const Color_Palette &best_palette, const Image &image, uniform_int_distribution<> &dis_h, uniform_int_distribution<> &dis_w){ int idx = rng() % k_Cnt_Colors; for(int i = 0; i < k_Cnt_Colors; ++i) palette[i] = best_palette[i]; int cnt_it = k_Iterations; while(cnt_it--){ palette[idx] = image[dis_h(rng)][dis_w(rng)]; bool ok = true; for(int j = 0; j < k_Cnt_Colors; ++j){ if(palette[idx] == best_palette[j]){ ok = false; break; } } if(ok) break; } } uniform_int_distribution<> dis_100(0, 99); inline bool percent_chance(int x){ return (dis_100(rng) < x); } void solve0(Image_Compressed& best_image, Color_Palette& best_palette, const short &h, const short &w, Image &image){ Color_Palette palette; long long ans = k_Inf_Long_Long; Image blurred_image(h, Row_Image(w)); for(short i = 0; i < k_Cnt_Colors; ++i){ for(short j = 0; j < 3; ++j){ palette[i][j] = 0; best_palette[i][j] = 0; } } uniform_int_distribution<> dis_h(0, h - 1), dis_w(0, w - 1); array, k_Cnt_Colors> sum; while(left_time() <= 4.5){ if(percent_chance(35)) get_new_random_palette(palette, image, dis_h, dis_w); else get_new_palette_by_changing_best(palette, best_palette, image, dis_h, dis_w); get_best_image(best_image, h, w, palette, image); for(short i = 0; i < k_Cnt_Colors; ++i) sum[i] = array{0, 0, 0, 0}; for(short i = 0; i < h; ++i){ for(short j = 0; j < w; ++j){ for(short k = 0; k < 3; ++k) sum[best_image[i][j]][k] += image[i][j][k]; ++sum[best_image[i][j]][3]; } } for(short i = 0; i < k_Cnt_Colors; ++i){ for(short j = 0; j < 3; ++j){ if(!sum[i][3]){ palette[i][j] = 0; continue; } if(sum[i][j] % sum[i][3] > sum[i][3] / 2) palette[i][j] = sum[i][j] / sum[i][3] + 1; else palette[i][j] = sum[i][j] / sum[i][3]; } } get_best_dithered_image(best_image, h, w, palette, image); get_blurred_image(blurred_image, h, w, palette, best_image); long long curr_ans = get_ans_for_image(blurred_image, h, w, image); if(curr_ans < ans){ best_palette = palette; ans = curr_ans; } } palette = best_palette; get_best_dithered_image(best_image, h, w, palette, image); } void solve1(Image &best_image, const short &h, const short &w, const Color_Palette &palette, Image_Compressed &image){ get_blurred_image(best_image, h, w, palette, image); } int main(){ ios::sync_with_stdio(false); cin.tie(NULL); freopen("imrec.in", "r", stdin); freopen("imrec.out", "w", stdout); bool run; short w, h; cin >> run; if(!run){ cin >> w >> h; Image image(h, Row_Image(w)); for(short i = 0; i < h; ++i) for(short j = 0; j < w; ++j) for(short k = 0; k < 3; ++k) cin >> image[i][j][k]; Image_Compressed best_image(h, Row_Image_Compressed(w)); Color_Palette best_palette; solve0(best_image, best_palette, h, w, image); for(Color color: best_palette){ for(short k = 0; k < 3; ++k) cout << color[k] << " "; cout << "\n"; } for(short i = 0; i < h; ++i){ for(short j = 0; j < w; ++j) cout << best_image[i][j] << " "; cout << "\n"; } return 0; } else{ Color_Palette palette; for(Color &color: palette) for(short &x: color) cin >> x; cin >> w >> h; Image_Compressed image(h, Row_Image_Compressed(w)); for(short i = 0; i < h; ++i) for(short j = 0; j < w; ++j) cin >> image[i][j]; Image best_image(h, Row_Image(w)); solve1(best_image, h, w, palette, image); for(short i = 0; i < h; ++i){ for(short j = 0; j < w; ++j){ for(short k = 0; k < 3; ++k) cout << best_image[i][j][k] << " "; cout << "\n"; } } }