#include using namespace std; constexpr int MAX_W = 300000; int edge_id(int n, int a, int b) { if (a > b) swap(a, b); if (b - a == n) return (a / n) * n + a % n; return n * (n - 1) + (a / n) * (n - 1) + a % n; } vector snake(int n) { vector p; for (int r = 0; r < n; ++r) { if (r % 2 == 0) for (int c = 0; c < n; ++c) p.push_back(r * n + c); else for (int c = n - 1; c >= 0; --c) p.push_back(r * n + c); } return p; } void output(int n, const vector& path_weight, int unused) { vector ans(2 * n * (n - 1), unused); auto p = snake(n); for (int i = 0; i + 1 < (int)p.size(); ++i) ans[edge_id(n, p[i], p[i + 1])] = path_weight[i]; int k = 0; for (int r = 0; r + 1 < n; ++r) { for (int c = 0; c < n; ++c) cout << (c ? " " : "") << ans[k++]; cout << '\n'; } for (int r = 0; r < n; ++r) { for (int c = 0; c + 1 < n; ++c) cout << (c ? " " : "") << ans[k++]; cout << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; int m = n * n; vector marks{0}; vector used(MAX_W); int candidate = 1; while ((int)marks.size() < m) { bool found = false; for (; candidate < MAX_W; ++candidate) { bool ok = true; for (int x : marks) if (used[candidate - x]) { ok = false; break; } if (!ok) continue; for (int x : marks) used[candidate - x] = 1; marks.push_back(candidate++); found = true; break; } if (!found) { cout << -1 << '\n'; return 0; } } vector w(m - 1); for (int i = 0; i + 1 < m; ++i) w[i] = marks[i + 1] - marks[i]; output(n, w, marks.back() + 1); }