516. 神奇的幻方
阿新 • • 發佈:2022-03-22
題目連結
516. 神奇的幻方
幻方是一種很神奇的 \(N \times N\) 矩陣: 它由數字 \(1,2,3, \ldots, N \times N\) 構成,且每行、每列及兩條對角線上的數 字之和都相同。
當 \(N\) 為奇數時,我們可以通過以下方法構建一個幻方:
首先將 1 寫在第一行的中間。
之後,按如下方式從小到大依次填寫每個數 \(K(K=2,3, \ldots, N \times N)\) :
- 若 \((K-1)\) 在第一行但不在最後一列,則將 \(K\) 填在最後一行, \((K-1)\) 所在列的右一列;
- 若 \((K-1)\) 在最後一列但不在第一行,則將 \(K\)
- 若 \((K-1)\) 在第一行最後一列,則將 \(K\) 填在 \((K-1)\) 的正下方;
- 若 \((K-1)\) 既不在第一行,也不在最後一列,如果 \((K-1)\) 的右上方還末填數,則將 \(K\) 填在 \((K-1)\) 的 右上方,否則將 \(K\) 填在 \((K-1)\) 的正下方。
現給定 \(N\) ,請按上述方法構造 \(N \times N\) 的幻方。
輸入格式
輸入檔案只有一行,包含一個整數 \(N\) ,即幻方的大小。
輸出格式
輸出檔案包含 \(N\) 行,每行 \(N\) 個整數,即按上述方法構造出的 \(N \times N\)
資料範圍
\(1≤N≤39\),\(N\) 為奇數。
輸入樣例:
3
輸出樣例:
8 1 6
3 5 7
4 9 2
解題思路
構造
對於奇數階幻方,先在第一行中間放置 \(1\),再向右上方放置數,如果右上方已經有數了,向下方放數,考慮特殊情況,如果當前數在右上角,則向下方放數,如果數越界了,則向對面放數
- 時間複雜度:\(O(n^2)\)
程式碼
// Problem: 神奇的幻方 // Contest: AcWing // URL: https://www.acwing.com/problem/content/518/ // Memory Limit: 16 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=40; int n; int a[N][N],t; int main() { cin>>n; int x=1,y=n/2+1; a[x][y]=++t; while(true) { if(x==1&&y==n) { x++; if(a[x][y])break; a[x][y]=++t; } else { if(x==1) { y++; x=n; if(a[x][y])break; a[x][y]=++t; } else if(y==n) { y=1; x--; if(a[x][y])break; a[x][y]=++t; } else { if(a[x-1][y+1]) { x++; if(a[x][y])break; a[x][y]=++t; } else { x--,y++; a[x][y]=++t; } } } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)cout<<a[i][j]<<(j<n?' ':'\n'); return 0; }