#include using namespace std; // min(H,W) <= 5 の構成 vector> build_small(int h, int w, int &C) { vector> a(h, vector(w)); if (h == 1) { C = w / 2 + 1; // 1 2 2 3 3 4 4 5 ... for (int j = 0; j < w; j++) { a[0][j] = (j + 1) / 2 + 1; } } else if (h == 2) { C = 2; for (int j = 0; j < w; j++) { a[0][j] = 1; a[1][j] = 2; } } else if (h == 3) { C = (w + 3) / 4 + 2; // ceil(w / 4) + 2 for (int j = 0; j < w; j++) { a[0][j] = 1; a[1][j] = 2; } int j = 0; int c = 3; // 2 c c 2 while (j + 4 <= w) { a[2][j] = 2; a[2][j + 1] = c; a[2][j + 2] = c; a[2][j + 3] = 2; c++; j += 4; } // w ≡ 2 (mod 4) if (j < w) { a[2][j] = 2; a[2][j + 1] = c; } } else if (h == 4) { C = 3; for (int j = 0; j < w; j++) { a[0][j] = 1; a[1][j] = 2; a[2][j] = 2; a[3][j] = 3; } } else { // h == 5 if (w == 6) { C = 3; a = { {3, 3, 3, 3, 3, 1}, {1, 1, 1, 1, 3, 1}, {1, 2, 1, 3, 3, 1}, {1, 2, 1, 1, 1, 1}, {1, 2, 2, 2, 2, 2}, }; } else if (w == 8) { C = 3; a = { {3, 3, 3, 3, 3, 3, 3, 1}, {1, 1, 1, 1, 1, 1, 3, 1}, {1, 2, 2, 1, 1, 3, 3, 1}, {1, 2, 1, 1, 1, 1, 1, 1}, {1, 2, 2, 2, 2, 2, 2, 2}, }; } else { C = 4; for (int j = 0; j < w; j++) { a[0][j] = 1; a[1][j] = 2; a[2][j] = (j % 2 == 0 ? 2 : 3); a[3][j] = 3; a[4][j] = 4; } } } return a; } // h,w >= 6 かつ w は偶数 vector> build_big(int h, int w, int &C) { C = 3; const int base6[6][6] = { {1, 1, 1, 1, 1, 3}, {2, 2, 2, 2, 1, 3}, {2, 1, 1, 1, 1, 3}, {2, 1, 3, 3, 1, 3}, {2, 1, 3, 3, 3, 3}, {2, 1, 1, 1, 1, 1}, }; // まず 6 x w に拡張する。 // 4 列目と 5 列目の間に、 // 元の 4 列目と同じ色配置の列を追加する。 vector> base(6, vector(w)); for (int i = 0; i < 6; i++) { int p = 0; for (int j = 0; j < 4; j++) { base[i][p++] = base6[i][j]; } for (int j = 0; j < w - 6; j++) { base[i][p++] = base6[i][3]; } base[i][p++] = base6[i][4]; base[i][p++] = base6[i][5]; } // 高さを増やす際に挿入する行。 // // 2 1 2 1 2 1 ... 1 3 // // w は偶数なので、横に 2 マスずつ組める。 vector mid(w); for (int j = 0; j < w - 2; j++) { mid[j] = (j % 2 == 0 ? 2 : 1); } mid[w - 2] = 1; mid[w - 1] = 3; vector> a; a.push_back(base[0]); a.push_back(base[1]); for (int i = 0; i < h - 6; i++) { a.push_back(mid); } for (int i = 2; i < 6; i++) { a.push_back(base[i]); } return a; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int H, W; cin >> H >> W; int C; vector> color; // H <= 5 の特殊ケースは、短い方を H として構成する。 if (min(H, W) <= 5) { bool transpose = (H > W); int h = min(H, W); int w = max(H, W); auto a = build_small(h, w, C); color.assign(H, vector(W)); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { color[i][j] = transpose ? a[j][i] : a[i][j]; } } } // 両辺 6 以上 else { // build_big では横幅を偶数にする。 // HW は偶数なので、W が奇数なら H は偶数。 bool transpose = (W % 2 == 1); int h = transpose ? W : H; int w = transpose ? H : W; auto a = build_big(h, w, C); color.assign(H, vector(W)); for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { color[i][j] = transpose ? a[j][i] : a[i][j]; } } } // ------------------------------------------------------------ // 以下、色の異なる隣接マスだけに辺を張り、 // 完全マッチングを求めてタイル配置を決める。 // ------------------------------------------------------------ int N = H * W; vector> graph(N); vector left; const int di[] = {1, -1, 0, 0}; const int dj[] = {0, 0, 1, -1}; for (int i = 0; i < H; i++) { for (int j = 0; j < W; j++) { if ((i + j) % 2) continue; int u = i * W + j; left.push_back(u); for (int d = 0; d < 4; d++) { int ni = i + di[d]; int nj = j + dj[d]; if (ni < 0 || ni >= H || nj < 0 || nj >= W) { continue; } if (color[i][j] == color[ni][nj]) { continue; } graph[u].push_back(ni * W + nj); } } } // Hopcroft-Karp vector mate(N, -1); vector dist(N); vector ptr(N); auto bfs = [&]() { queue q; fill(dist.begin(), dist.end(), -1); bool found = false; for (int u : left) { if (mate[u] == -1) { dist[u] = 0; q.push(u); } } while (!q.empty()) { int u = q.front(); q.pop(); for (int v : graph[u]) { int nu = mate[v]; if (nu == -1) { found = true; } else if (dist[nu] == -1) { dist[nu] = dist[u] + 1; q.push(nu); } } } return found; }; function dfs = [&](int u) { for (int &k = ptr[u]; k < (int)graph[u].size(); k++) { int v = graph[u][k]; int nu = mate[v]; if (nu == -1 || (dist[nu] == dist[u] + 1 && dfs(nu))) { mate[u] = v; mate[v] = u; return true; } } dist[u] = -1; return false; }; int matched = 0; while (bfs()) { fill(ptr.begin(), ptr.end(), 0); for (int u : left) { if (mate[u] == -1 && dfs(u)) { matched++; } } } assert(matched * 2 == N); // 出力 cout << C << '\n'; for (int u : left) { int v = mate[u]; int x1 = u / W; int y1 = u % W; int x2 = v / W; int y2 = v % W; cout << x1 + 1 << ' ' << y1 + 1 << ' ' << color[x1][y1] << ' ' << x2 + 1 << ' ' << y2 + 1 << ' ' << color[x2][y2] << '\n'; } }