mayoko’s diary

プロコンとかいろいろ。

SRM 593 div1 easy: HexagonalBoard

解法

4 色定理とかあるので, せいぜい 4 色あれば塗りきれることがわかりますが, 実は今回の場合はせいぜい 3 色あれば塗りきれることがわかります。

例えば n = 4 の場合は, 以下のようにすれば良いです。

RBGR
GRBG
BGRB
RBGR

一番上の辺を RBG を繰り返すように塗って, そこから下は 上, 左と色が異なるように塗ると, OK です。

  • 0 色で足りるのは何も塗らない場合
  • 1 色で足りるのはどの頂点も隣接していない場合
  • 2 色で足りるのは貪欲に頂点の色を入れ替えして OK な場合

で, 以上の場合でダメな場合は 3 が答えになります。

int color[55*55];

bool dfs(int v, int c, const vector<vi>& G) {
    color[v] = c;
    for (int ch : G[v]) {
        if (color[ch] == 0) {
            if (!dfs(ch, -c, G)) return false;
        } else if (color[ch] == c) return false;
    }
    return true;
}

class HexagonalBoard {
public:
    int minColors(vector <string> board) {
        int n = board.size();
        vector<vi> G(n*n);
        bool is0 = true;
        for (int y = 0; y < n; y++) for (int x = 0; x < n; x++) {
            if (board[y][x] == 'X') {
                is0 = false;
                for (int k = 0; k < 6; k++) {
                    int ny = y+dy[k], nx = x+dx[k];
                    if (ny < 0 || ny >= n || nx < 0 || nx >= n) continue;
                    if (board[ny][nx] == 'X') {
                        G[y*n+x].push_back(ny*n+nx);
                    }
                }
            }
        }
        if (is0) return 0;
        bool is1 = true;
        for (int i = 0; i < n*n; i++) if (G[i].size() > 0) is1 = false;
        if (is1) return 1;
        memset(color, 0, sizeof(color));
        for (int i = 0; i < n*n; i++) {
            if (G[i].size() > 0 && color[i] == 0) {
                if (!dfs(i, 1, G)) return 3;
            }
        }
        return 2;
    }
};