| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| static const int KMAX = 240; |
|
|
| struct RNG { |
| uint64_t seed; |
| RNG(uint64_t s=123456789) : seed(s) {} |
| inline uint64_t next() { |
| seed ^= seed << 7; |
| seed ^= seed >> 9; |
| return seed; |
| } |
| inline int randint(int n) { |
| return (int)(next() % (uint64_t)n); |
| } |
| inline bool coin() { return (next() >> 63) & 1; } |
| }; |
|
|
| struct WorldMapBuilder { |
| int N, M; |
| vector<int> A, B; |
| vector<vector<char>> adj; |
| vector<vector<char>> allow; |
|
|
| int K; |
| vector<vector<int>> grid; |
|
|
| RNG rng; |
|
|
| WorldMapBuilder(int n, int m, const vector<int>& a, const vector<int>& b, uint64_t seed) |
| : N(n), M(m), A(a), B(b), adj(n, vector<char>(n, 0)), allow(n, vector<char>(n, 0)), rng(seed) { |
| for (int i = 0; i < M; ++i) { |
| int u = A[i]-1; |
| int v = B[i]-1; |
| adj[u][v] = adj[v][u] = 1; |
| } |
| for (int i = 0; i < N; ++i) { |
| allow[i][i] = 1; |
| for (int j = 0; j < N; ++j) if (adj[i][j]) allow[i][j] = 1; |
| } |
| |
| K = min(KMAX, max(2*N, 100)); |
| grid.assign(K, vector<int>(K, 0)); |
| } |
|
|
| vector<int> dfs_walk() { |
| vector<vector<int>> G(N); |
| for (int u = 0; u < N; ++u) for (int v = 0; v < N; ++v) if (adj[u][v]) G[u].push_back(v); |
| |
| for (int u = 0; u < N; ++u) { |
| for (int i = (int)G[u].size()-1; i > 0; --i) { |
| int j = rng.randint(i+1); |
| swap(G[u][i], G[u][j]); |
| } |
| } |
| vector<int> walk; |
| vector<char> vis(N, 0); |
| int root = 0; |
| |
| function<void(int,int)> dfs = [&](int u, int p){ |
| vis[u] = 1; |
| walk.push_back(u); |
| for (int v : G[u]) { |
| if (!vis[v]) { |
| dfs(v, u); |
| walk.push_back(u); |
| } |
| } |
| }; |
| dfs(root, -1); |
| if (walk.empty()) walk.push_back(0); |
| |
| if (walk.back() != root) walk.push_back(root); |
| return walk; |
| } |
|
|
| inline void markEdge(int u, int v, vector<vector<char>>& covered) { |
| if (u == v) return; |
| if (!adj[u][v]) return; |
| int x = min(u, v), y = max(u, v); |
| covered[x][y] = 1; |
| } |
|
|
| void collectCovered(const vector<vector<int>>& g, vector<vector<char>>& covered) { |
| for (int i = 0; i < N; ++i) for (int j = i+1; j < N; ++j) covered[i][j] = 0; |
| for (int r = 0; r < K; ++r) { |
| for (int c = 1; c < K; ++c) markEdge(g[r][c-1], g[r][c], covered); |
| } |
| for (int r = 1; r < K; ++r) { |
| for (int c = 0; c < K; ++c) markEdge(g[r-1][c], g[r][c], covered); |
| } |
| } |
|
|
| vector<int> build_first_row_from_walk(const vector<int>& walk) { |
| vector<int> row(K); |
| for (int c = 0; c < K; ++c) row[c] = walk[c % (int)walk.size()]; |
| return row; |
| } |
|
|
| |
| |
| |
| |
| vector<int> compute_row_dp(const vector<int>* top, const vector<vector<char>>& covered, int force_u = -1, int force_v = -1) { |
| bool enforce = (force_u != -1 && force_v != -1); |
| |
| vector<vector<int>> allowedCols(K); |
| if (top) { |
| allowedCols.assign(K, {}); |
| for (int c = 0; c < K; ++c) { |
| int t = (*top)[c]; |
| for (int x = 0; x < N; ++x) if (allow[x][t]) allowedCols[c].push_back(x); |
| |
| for (int i = (int)allowedCols[c].size()-1; i > 0; --i) { |
| int j = rng.randint(i+1); |
| swap(allowedCols[c][i], allowedCols[c][j]); |
| } |
| } |
| } else { |
| vector<int> all(N); |
| iota(all.begin(), all.end(), 0); |
| for (int c = 0; c < K; ++c) { |
| allowedCols[c] = all; |
| for (int i = N-1; i > 0; --i) { |
| int j = rng.randint(i+1); |
| swap(allowedCols[c][i], allowedCols[c][j]); |
| } |
| } |
| } |
|
|
| const int NEG = -1e9; |
| |
| vector<array<int,2>> dp_prev(N, {NEG, NEG}), dp_cur(N, {NEG, NEG}); |
| vector<vector<array<int,2>>> prv(K, vector<array<int,2>>(N, array<int,2>{-1,-1})); |
|
|
| auto wantEdge = [&](int a, int b)->bool{ |
| if (a==b) return false; |
| int x = min(a,b), y = max(a,b); |
| if (!adj[x][y]) return false; |
| return !covered[x][y]; |
| }; |
|
|
| auto trans_w = [&](int y, int x)->int{ |
| if (y == x) return 0; |
| return wantEdge(y, x) ? 2 : 0; |
| }; |
| auto node_w = [&](int c, int x)->int{ |
| if (!top) return 0; |
| int t = (*top)[c]; |
| if (t == x) return 0; |
| return wantEdge(t, x) ? 1 : 0; |
| }; |
|
|
| |
| for (int x : allowedCols[0]) { |
| int used = 0; |
| dp_prev[x][0] = node_w(0, x); |
| dp_prev[x][1] = NEG; |
| } |
|
|
| |
| for (int c = 1; c < K; ++c) { |
| |
| for (int x = 0; x < N; ++x) dp_cur[x][0] = dp_cur[x][1] = NEG; |
| for (int x : allowedCols[c]) { |
| int nw = node_w(c, x); |
| for (int y : allowedCols[c-1]) { |
| if (!allow[y][x]) continue; |
| |
| if (dp_prev[y][0] > NEG/2) { |
| int inc = trans_w(y, x) + nw; |
| int used = 0; |
| if (enforce && ((y==force_u && x==force_v) || (y==force_v && x==force_u))) used = 1; |
| int cand = dp_prev[y][0] + inc; |
| if (cand > dp_cur[x][used] || (cand == dp_cur[x][used] && rng.coin())) { |
| dp_cur[x][used] = cand; |
| prv[c][x][used] = y; |
| } |
| } |
| |
| if (dp_prev[y][1] > NEG/2) { |
| int inc = trans_w(y, x) + nw; |
| int used = 1; |
| int cand = dp_prev[y][1] + inc; |
| if (cand > dp_cur[x][used] || (cand == dp_cur[x][used] && rng.coin())) { |
| dp_cur[x][used] = cand; |
| prv[c][x][used] = y; |
| } |
| } |
| } |
| } |
| |
| for (int x = 0; x < N; ++x) { |
| dp_prev[x][0] = dp_cur[x][0]; |
| dp_prev[x][1] = dp_cur[x][1]; |
| dp_cur[x][0] = dp_cur[x][1] = NEG; |
| } |
| } |
|
|
| |
| int best_used = enforce ? 1 : 0; |
| int best_x = -1, best_val = NEG; |
| for (int x : allowedCols[K-1]) { |
| for (int u = (enforce?1:0); u <= 1; ++u) { |
| if (!enforce && u==0) { |
| if (dp_prev[x][u] > best_val || (dp_prev[x][u] == best_val && rng.coin())) { |
| best_val = dp_prev[x][u]; |
| best_x = x; |
| best_used = u; |
| } |
| } else if (enforce && u==1) { |
| if (dp_prev[x][u] > best_val || (dp_prev[x][u] == best_val && rng.coin())) { |
| best_val = dp_prev[x][u]; |
| best_x = x; |
| best_used = u; |
| } |
| } else if (!enforce && u==1) { |
| if (dp_prev[x][u] > best_val || (dp_prev[x][u] == best_val && rng.coin())) { |
| best_val = dp_prev[x][u]; |
| best_x = x; |
| best_used = u; |
| } |
| } |
| } |
| } |
| if (best_x == -1) { |
| |
| vector<int> fallback(K); |
| if (top) { |
| fallback = *top; |
| } else { |
| for (int c = 0; c < K; ++c) fallback[c] = rng.randint(N); |
| } |
| return fallback; |
| } |
|
|
| |
| vector<int> row(K); |
| int x = best_x; |
| int used = best_used; |
| for (int c = K-1; c >= 0; --c) { |
| row[c] = x; |
| if (c == 0) break; |
| int y = prv[c][x][used]; |
| if (enforce) { |
| |
| if (used == 1) { |
| if ((y==force_u && x==force_v) || (y==force_v && x==force_u)) { |
| |
| |
| |
| |
| |
| |
| |
| used = 0; |
| } |
| } |
| } |
| x = y; |
| } |
| return row; |
| } |
|
|
| void update_covered_with_row(int r, const vector<int>* top, const vector<int>& row, vector<vector<char>>& covered) { |
| |
| for (int c = 1; c < K; ++c) markEdge(row[c-1], row[c], covered); |
| if (top) { |
| for (int c = 0; c < K; ++c) markEdge((*top)[c], row[c], covered); |
| } |
| } |
|
|
| bool all_edges_covered(const vector<vector<char>>& covered) { |
| for (int i = 0; i < M; ++i) { |
| int u = A[i]-1, v = B[i]-1; |
| int x = min(u, v), y = max(u, v); |
| if (!covered[x][y]) return false; |
| } |
| return true; |
| } |
|
|
| vector<pair<int,int>> missing_edges(const vector<vector<char>>& covered) { |
| vector<pair<int,int>> miss; |
| for (int i = 0; i < M; ++i) { |
| int u = A[i]-1, v = B[i]-1; |
| int x = min(u, v), y = max(u, v); |
| if (!covered[x][y]) miss.emplace_back(x, y); |
| } |
| return miss; |
| } |
|
|
| vector<vector<int>> build_once() { |
| vector<vector<int>> g(K, vector<int>(K, 0)); |
| vector<vector<char>> covered(N, vector<char>(N, 0)); |
| |
| vector<int> walk = dfs_walk(); |
| vector<int> row0 = build_first_row_from_walk(walk); |
| g[0] = row0; |
| |
| update_covered_with_row(0, nullptr, row0, covered); |
| |
| for (int r = 1; r < K; ++r) { |
| vector<int> rowr = compute_row_dp(&g[r-1], covered, -1, -1); |
| g[r] = rowr; |
| update_covered_with_row(r, &g[r-1], rowr, covered); |
| } |
| |
| vector<int> freq(N, 0); |
| for (int r = 0; r < K; ++r) for (int c = 0; c < K; ++c) freq[g[r][c]]++; |
| for (int col = 0; col < N; ++col) { |
| if (freq[col] == 0) { |
| |
| int r = rng.randint(K); |
| vector<int> rowr = compute_row_dp((r>0 ? &g[r-1] : nullptr), covered, -1, -1); |
| g[r] = rowr; |
| |
| |
| for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) covered[i][j] = 0; |
| update_covered_with_row(0, nullptr, g[0], covered); |
| for (int i = 1; i <= r; ++i) update_covered_with_row(i, &g[i-1], g[i], covered); |
| for (int i = r+1; i < K; ++i) { |
| vector<int> rowi = compute_row_dp(&g[i-1], covered, -1, -1); |
| g[i] = rowi; |
| update_covered_with_row(i, &g[i-1], g[i], covered); |
| } |
| |
| freq.assign(N, 0); |
| for (int rr = 0; rr < K; ++rr) for (int c = 0; c < K; ++c) freq[g[rr][c]]++; |
| } |
| } |
| return g; |
| } |
|
|
| vector<vector<int>> repair_missing(vector<vector<int>>& g) { |
| |
| vector<vector<char>> covered(N, vector<char>(N, 0)); |
| collectCovered(g, covered); |
| auto miss = missing_edges(covered); |
| if (miss.empty()) return g; |
|
|
| |
| |
| for (int i = (int)miss.size()-1; i > 0; --i) { |
| int j = rng.randint(i+1); |
| swap(miss[i], miss[j]); |
| } |
|
|
| for (auto edge : miss) { |
| int fu = edge.first, fv = edge.second; |
| bool added = false; |
| |
| vector<int> rows(K); |
| iota(rows.begin(), rows.end(), 0); |
| for (int i = K-1; i > 0; --i) { |
| int j = rng.randint(i+1); |
| swap(rows[i], rows[j]); |
| } |
| for (int rindex = 0; rindex < K && !added; ++rindex) { |
| int r = rows[rindex]; |
| vector<vector<char>> covUp = covered; |
| |
| for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) covUp[i][j] = 0; |
| update_covered_with_row(0, nullptr, g[0], covUp); |
| for (int i = 1; i < r; ++i) update_covered_with_row(i, &g[i-1], g[i], covUp); |
|
|
| vector<int>* top = (r > 0 ? &g[r-1] : nullptr); |
| vector<int> newRow = compute_row_dp(top, covUp, fu, fv); |
| if (newRow.empty()) continue; |
|
|
| |
| g[r] = newRow; |
| |
| vector<vector<char>> cov(N, vector<char>(N, 0)); |
| update_covered_with_row(0, nullptr, g[0], cov); |
| for (int i = 1; i <= r; ++i) update_covered_with_row(i, &g[i-1], g[i], cov); |
| for (int i = r+1; i < K; ++i) { |
| vector<int> ri = compute_row_dp(&g[i-1], cov, -1, -1); |
| g[i] = ri; |
| update_covered_with_row(i, &g[i-1], g[i], cov); |
| } |
|
|
| |
| vector<vector<char>> covCheck(N, vector<char>(N, 0)); |
| collectCovered(g, covCheck); |
| if (covCheck[fu][fv]) { |
| covered = covCheck; |
| added = true; |
| } |
| } |
| if (!added) { |
| |
| return g; |
| } |
| } |
| return g; |
| } |
|
|
| vector<vector<int>> build_map() { |
| |
| for (int attempt = 0; attempt < 8; ++attempt) { |
| auto g = build_once(); |
| vector<vector<char>> covered(N, vector<char>(N, 0)); |
| collectCovered(g, covered); |
| if (all_edges_covered(covered)) { |
| grid = g; |
| return format_output(); |
| } |
| auto g2 = repair_missing(g); |
| collectCovered(g2, covered); |
| if (all_edges_covered(covered)) { |
| grid = g2; |
| return format_output(); |
| } |
| |
| if (K < KMAX) { |
| K = min(KMAX, K + max(5, N/2)); |
| grid.assign(K, vector<int>(K, 0)); |
| } |
| |
| rng.next(); |
| } |
| |
| K = min(KMAX, max(2*N, 100)); |
| grid.assign(K, vector<int>(K, 0)); |
| vector<int> walk = dfs_walk(); |
| for (int r = 0; r < K; ++r) { |
| auto row0 = build_first_row_from_walk(walk); |
| for (int c = 0; c < K; ++c) grid[r][c] = row0[c]; |
| } |
| return format_output(); |
| } |
|
|
| vector<vector<int>> format_output() { |
| vector<vector<int>> C(K, vector<int>(K, 0)); |
| for (int r = 0; r < K; ++r) for (int c = 0; c < K; ++c) C[r][c] = grid[r][c] + 1; |
| return C; |
| } |
| }; |
|
|
| vector<vector<int>> create_map(int N, int M, vector<int> A, vector<int> B) { |
| |
| uint64_t seed = 1469598103934665603ull; |
| seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); |
| seed ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); |
| for (int x : A) { seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); } |
| for (int x : B) { seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ull + (seed<<6) + (seed>>2); } |
|
|
| WorldMapBuilder builder(N, M, A, B, seed); |
| return builder.build_map(); |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
| int T; |
| if (!(cin >> T)) return 0; |
| for (int tc = 0; tc < T; ++tc) { |
| int N, M; |
| cin >> N >> M; |
| vector<int> A(M), B(M); |
| for (int i = 0; i < M; ++i) cin >> A[i] >> B[i]; |
| auto 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':' '); |
| } |
| cout << "\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"; |
| } |
| cout.flush(); |
| } |
| return 0; |
| } |