「前処理」を学べる問題ですね。
問題概要
色が全部で 色ある。
× の盤面がそれぞれ 色のいずれかに塗られている。今この盤面の色を塗り替えて
- マス () について % 3 の値によって色を類別された状態 (その値が同じマスは同じ色に、違うマスは違う色に)
にしたい。色 のマスを色 にするのにかかるコストは として与えられている。最小コストで目的を達成せよ。
制約
考えたこと
% 3 の値は 3 通りなので、調べるべき場合は 通りである。素直な全探索で解ける問題なのだが...
愚直にやろうと思うと、 通りそれぞれについて、 個のマスにかかるコストを総和をとるような処理をしたくなり、これでは計算量は かかってしまう。
これでは間に合わないので、 % 3 の 3 通りの値それぞれについて、その値のマスすべてを 色にするのに必要な総コストを前処理しておく。この前処理にかかる時間は である。
この前処理をしておくと、上述の全探索の 通りそれぞれについてのコスト計算は でできるので でできる。まとめると
- 前処理:
- 全探索:
ともにちゃんと間に合う
#include <iostream> #include <vector> using namespace std; int main() { // 入力 int N, C; cin >> N >> C; vector<vector<int> > D(C, vector<int>(C, 0)); for (int i = 0; i < C; ++i) for (int j = 0; j < C; ++j) cin >> D[i][j]; vector<vector<int> > fi(N, vector<int>(N, 0)); for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) cin >> fi[i][j], --fi[i][j]; // 前処理 vector<vector<int> > cost(3, vector<int>(C, 0)); for (int c = 0; c < C; ++c) { for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) { cost[(i+j)%3][c] += D[fi[i][j]][c]; } } } // 求める int res = 1<<30; int c[3]; for (c[0] = 0; c[0] < C; ++c[0]) { for (c[1] = 0; c[1] < C; ++c[1]) { if (c[1] == c[0]) continue; for (c[2] = 0; c[2] < C; ++c[2]) { if (c[2] == c[0] || c[2] == c[1]) continue; int tmp = 0; for (int it = 0; it < 3; ++it) tmp += cost[it][c[it]]; res = min(res, tmp); } } } cout << res << endl; }