#include using namespace std; using ll = long long; using Clock = chrono::steady_clock; constexpr int MAX_W = 300000; constexpr double TIME_LIMIT = 1.9; struct Edge { int u, v, w; }; struct Pair { int s, t; }; vector make_edges(int n) { vector e; for (int r = 0; r + 1 < n; ++r) for (int c = 0; c < n; ++c) e.push_back({r * n + c, (r + 1) * n + c, 1}); for (int r = 0; r < n; ++r) for (int c = 0; c + 1 < n; ++c) e.push_back({r * n + c, r * n + c + 1, 1}); return e; } vector>> graph(int v, const vector& e) { vector>> g(v); for (int i = 0; i < (int)e.size(); ++i) { g[e[i].u].push_back({e[i].v, i}); g[e[i].v].push_back({e[i].u, i}); } return g; } // trueなら重複を発見。time_upなら探索を打ち切った。 bool collision(int v, const vector& e, const vector>>& g, Pair& a, Pair& b, Clock::time_point deadline, bool& time_up) { unordered_map seen; seen.reserve((size_t)v * (v - 1) / 2); vector dist(v); for (int s = 0; s < v; ++s) { if (Clock::now() >= deadline) { time_up = true; return false; } fill(dist.begin(), dist.end(), (1LL << 60)); priority_queue, vector>, greater>> pq; dist[s] = 0; pq.push({0, s}); while (!pq.empty()) { auto [d, x] = pq.top(); pq.pop(); if (d != dist[x]) continue; for (auto [y, id] : g[x]) if (dist[y] > d + e[id].w) { dist[y] = d + e[id].w; pq.push({dist[y], y}); } } for (int t = s + 1; t < v; ++t) { auto [it, fresh] = seen.emplace(dist[t], Pair{s, t}); if (!fresh) { a = it->second; b = {s, t}; return true; } } } return false; } vector shortest_path(Pair p, const vector& e, const vector>>& g) { int v = g.size(); vector dist(v, (1LL << 60)); vector pv(v, -1), pe(v, -1); priority_queue, vector>, greater>> pq; dist[p.s] = 0; pq.push({0, p.s}); while (!pq.empty()) { auto [d, x] = pq.top(); pq.pop(); if (d != dist[x]) continue; for (auto [y, id] : g[x]) if (dist[y] > d + e[id].w) { dist[y] = d + e[id].w; pv[y] = x; pe[y] = id; pq.push({dist[y], y}); } } vector path; for (int x = p.t; x != p.s; x = pv[x]) path.push_back(pe[x]); return path; } void output(int n, const vector& e) { int k = 0; for (int r = 0; r + 1 < n; ++r) { for (int c = 0; c < n; ++c) cout << (c ? " " : "") << e[k++].w; cout << '\n'; } for (int r = 0; r < n; ++r) { for (int c = 0; c + 1 < n; ++c) cout << (c ? " " : "") << e[k++].w; cout << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; int v = n * n; auto e = make_edges(n); auto g = graph(v, e); mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution weight(1, MAX_W); auto deadline = Clock::now() + chrono::duration_cast(chrono::duration(TIME_LIMIT)); int steps = 0; for (auto& x : e) x.w = weight(rng); while (Clock::now() < deadline) { Pair a, b; bool time_up = false; bool bad = collision(v, e, g, a, b, deadline, time_up); if (time_up) break; if (!bad) { output(n, e); return 0; } Pair chosen = (rng() & 1) ? a : b; auto path = shortest_path(chosen, e, g); int id = path[rng() % path.size()]; int delta = (rng() & 1) ? 1 : -1; if (e[id].w + delta < 1 || e[id].w + delta > MAX_W) delta = -delta; e[id].w += delta; if (++steps % 2000 == 0) for (auto& x : e) x.w = weight(rng); } cout << -1 << '\n'; }