#include using namespace std; struct Solver { int N, M; vector A, B; bool need[41][41]; mt19937_64 rng; Solver(int n, int m, const vector& a, const vector& b) : N(n), M(m), A(a), B(b) { memset(need, 0, sizeof(need)); for (int i = 0; i < M; ++i) { int u = A[i]; int v = B[i]; if (u > v) swap(u, v); need[u][v] = true; } rng.seed((uint64_t)chrono::high_resolution_clock::now().time_since_epoch().count()); } pair>> attempt(int K) { const int PEN_MISS = 10; const int PEN_FORBID = 100; const int PEN_UNUSED = 50; vector> grid(K, vector(K)); vector colorCount(N + 1, 0); int curAdj[41][41]; memset(curAdj, 0, sizeof(curAdj)); uniform_int_distribution colorDist(1, N); // Initial random grid for (int r = 0; r < K; ++r) { for (int c = 0; c < K; ++c) { int col = colorDist(rng); grid[r][c] = col; } } // Ensure each color appears at least once in first N cells for (int i = 0; i < N; ++i) { int r = i / K; int c = i % K; grid[r][c] = i + 1; } // Recompute colorCount and adjacency auto recompute_all = [&]() -> int { fill(colorCount.begin(), colorCount.end(), 0); memset(curAdj, 0, sizeof(curAdj)); for (int r = 0; r < K; ++r) { for (int c = 0; c < K; ++c) { int col = grid[r][c]; colorCount[col]++; } } for (int r = 0; r < K; ++r) { for (int c = 0; c < K; ++c) { int col = grid[r][c]; if (c + 1 < K) { int col2 = grid[r][c + 1]; if (col != col2) { int i = min(col, col2); int j = max(col, col2); curAdj[i][j]++; } } if (r + 1 < K) { int col2 = grid[r + 1][c]; if (col != col2) { int i = min(col, col2); int j = max(col, col2); curAdj[i][j]++; } } } } int pen = 0; for (int col = 1; col <= N; ++col) { if (colorCount[col] == 0) pen += PEN_UNUSED; } for (int i = 1; i <= N; ++i) { for (int j = i + 1; j <= N; ++j) { int cnt = curAdj[i][j]; if (need[i][j]) { if (cnt == 0) pen += PEN_MISS; } else { if (cnt > 0) pen += PEN_FORBID; } } } return pen; }; int totalPenalty = recompute_all(); vector> bestGrid = grid; int bestPenalty = totalPenalty; if (bestPenalty == 0) return {0, bestGrid}; long long TOT_ITERS = 400LL * K * K; if (TOT_ITERS < 20000) TOT_ITERS = 20000; const double Tstart = 2.0; const double Tend = 0.01; double alpha = pow(Tend / Tstart, 1.0 / (double)TOT_ITERS); double T = Tstart; uniform_real_distribution realDist(0.0, 1.0); struct PairDelta { int u, v; int delta; }; for (long long it = 0; it < TOT_ITERS && bestPenalty > 0; ++it) { int r = (int)(rng() % K); int c = (int)(rng() % K); int oldColor = grid[r][c]; if (N == 1) break; // should not happen here because N>1 in this attempt int newColor = (int)(rng() % (N - 1)) + 1; if (newColor >= oldColor) ++newColor; if (newColor == oldColor) continue; int deltaColor = 0; int oldCountA = colorCount[oldColor]; int oldCountB = colorCount[newColor]; if (oldCountA == 1) deltaColor += PEN_UNUSED; if (oldCountB == 0) deltaColor -= PEN_UNUSED; PairDelta pd[8]; int pdSize = 0; auto addDelta = [&](int u, int v, int d) { if (u == v) return; if (u > v) swap(u, v); for (int k = 0; k < pdSize; ++k) { if (pd[k].u == u && pd[k].v == v) { pd[k].delta += d; return; } } pd[pdSize].u = u; pd[pdSize].v = v; pd[pdSize].delta = d; ++pdSize; }; auto process_neighbor = [&](int nr, int nc) { int x = grid[nr][nc]; if (x == oldColor) { if (newColor != x) { addDelta(min(newColor, x), max(newColor, x), +1); } } else if (x == newColor) { addDelta(min(oldColor, x), max(oldColor, x), -1); } else { addDelta(min(oldColor, x), max(oldColor, x), -1); addDelta(min(newColor, x), max(newColor, x), +1); } }; if (r > 0) process_neighbor(r - 1, c); if (r + 1 < K) process_neighbor(r + 1, c); if (c > 0) process_neighbor(r, c - 1); if (c + 1 < K) process_neighbor(r, c + 1); int deltaEdges = 0; for (int k = 0; k < pdSize; ++k) { int u = pd[k].u; int v = pd[k].v; int d = pd[k].delta; if (d == 0) continue; int oldCnt = curAdj[u][v]; int newCnt = oldCnt + d; int oldP, newP; if (need[u][v]) { oldP = (oldCnt == 0 ? PEN_MISS : 0); newP = (newCnt == 0 ? PEN_MISS : 0); } else { oldP = (oldCnt > 0 ? PEN_FORBID : 0); newP = (newCnt > 0 ? PEN_FORBID : 0); } deltaEdges += newP - oldP; } int delta = deltaColor + deltaEdges; int newPenalty = totalPenalty + delta; bool accept = false; if (delta <= 0) { accept = true; } else { double prob = exp(- (double)delta / T); if (realDist(rng) < prob) accept = true; } if (accept) { grid[r][c] = newColor; colorCount[oldColor]--; colorCount[newColor]++; for (int k = 0; k < pdSize; ++k) { int u = pd[k].u; int v = pd[k].v; int d = pd[k].delta; if (d != 0) curAdj[u][v] += d; } totalPenalty = newPenalty; if (totalPenalty < bestPenalty) { bestPenalty = totalPenalty; bestGrid = grid; if (bestPenalty == 0) break; } } T *= alpha; if (T < Tend) T = Tend; } return {bestPenalty, bestGrid}; } vector> solve() { if (N == 1) { return vector>(1, vector(1, 1)); } int K = min(240, max(3 * N, 5)); int bestPenalty = INT_MAX; vector> bestGrid; int TRIES = 3; for (int t = 0; t < TRIES; ++t) { auto res = attempt(K); if (res.first < bestPenalty) { bestPenalty = res.first; bestGrid = res.second; } if (bestPenalty == 0) break; } // As a fallback, if somehow not perfect, just return bestGrid (may be invalid in worst case). return bestGrid; } }; vector> create_map(int N, int M, vector A, vector B) { Solver solver(N, M, A, B); return solver.solve(); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; if (!(cin >> T)) return 0; while (T--) { int N, M; cin >> N >> M; vector A(M), B(M); for (int i = 0; i < M; ++i) cin >> A[i] >> B[i]; vector> C = create_map(N, M, A, B); int P = (int)C.size(); cout << P << "\n"; for (int i = 0; i < P; ++i) { cout << (int)C[i].size() << (i + 1 == P ? '\n' : ' '); } for (int i = 0; i < P; ++i) { for (int j = 0; j < (int)C[i].size(); ++j) { if (j) cout << ' '; cout << C[i][j]; } cout << "\n"; } } return 0; }