week4-[二维数组]幻方检测
week4-[二维数组]幻方检测
题目描述
幻方是一种很神奇的 NNN 行 NNN 列的方阵:它由数字 1,2,3,…,N×N1,2,3,\ldots,N\times N1,2,3,…,N×N 构成,其中1,2,3,…,N×N1,2,3,\ldots,N\times N1,2,3,…,N×N中每个数字在幻方中出现恰好一次,并且每行、每列及两条对角线上的数字之和都相同。
给定一个 NNN 行 NNN 列的整数方阵,其中第 iii 行 第 jjj 列的数字为 Ai,jA_{i,j}Ai,j。请判断该整数方阵是否为幻方。
输入格式
第一行包括一个整数 NNN,表示幻方的阶数。
接下来 NNN 行,每行 NNN 个整数,表示待检测的数字方阵 AAA 。
输出格式
如果输入的方阵 AAA 为幻方,则输出一行"Yes",否则输出一行"No"(输出的内容不包括引号)。
样例 #1
样例输入 #1
3
6 7 2
1 5 9
8 3 4
样例输出 #1
Yes
样例 #2
样例输入 #2
3
4 3 8
9 5 1
2 7 6
样例输出 #2
Yes
样例 #3
样例输入 #3
4
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
样例输出 #3
Yes
样例 #4
样例输入 #4
3
3 1 2
1 2 3
2 3 1
样例输出 #4
No
样例 #5
样例输入 #5
3
5 6 1
0 4 8
7 2 3
样例输出 #5
No
提示
数据范围
对于所有数据,3≤N≤30,0≤Ai,j≤10003 \le N \le 30,0 \le A_{i,j} \le 10003≤N≤30,0≤Ai,j≤1000。
🔎 解题思路
一个矩阵要成为「幻方」,必须同时满足两个条件:
- 数字完整性:矩阵里的数字必须是
1 ~ N*N
,每个出现且只出现一次。- 可以用一个布尔数组(或 set)来检查。
- 行列与对角线和相等:
- 先计算第一行的和作为目标值
target
。 - 依次检查每一行、每一列是否和
target
相等。 - 检查两条对角线是否和
target
相等。
- 先计算第一行的和作为目标值
只要有一条不满足,答案就是 "No"
。
📝 算法步骤
- 读入 N 和矩阵。
- 检查数字范围与唯一性:
- 开一个大小
N*N+1
的布尔数组used
。 - 遍历矩阵元素,如果数字不在
1 ~ N*N
范围内或重复,直接输出"No"
。
- 开一个大小
- 计算目标和
target
= 第一行的和。 - 逐行逐列检查:
- 遍历所有行、列的和是否等于
target
。
- 遍历所有行、列的和是否等于
- 检查两条对角线:
- 主对角线:
A[1][1] + A[2][2] + ... + A[N][N]
- 副对角线:
A[1][N] + A[2][N-1] + ... + A[N][1]
- 主对角线:
- 如果所有条件都满足,输出
"Yes"
,否则输出"No"
。
🧾 C++ 代码实现
#include <iostream>
#include <vector>
using namespace std;int main() {int N;cin >> N;vector<vector<int>> A(N, vector<int>(N));vector<bool> used(N * N + 1, false);// 读入并检查数字范围for (int i = 0; i < N; i++) {for (int j = 0; j < N; j++) {cin >> A[i][j];int val = A[i][j];if (val < 1 || val > N * N || used[val]) {cout << "No" << endl;return 0;}used[val] = true;}}// 目标和:第一行int target = 0;for (int j = 0; j < N; j++) target += A[0][j];// 检查每一行for (int i = 0; i < N; i++) {int sumRow = 0;for (int j = 0; j < N; j++) sumRow += A[i][j];if (sumRow != target) {cout << "No" << endl;return 0;}}// 检查每一列for (int j = 0; j < N; j++) {int sumCol = 0;for (int i = 0; i < N; i++) sumCol += A[i][j];if (sumCol != target) {cout << "No" << endl;return 0;}}// 主对角线int sumDiag1 = 0, sumDiag2 = 0;for (int i = 0; i < N; i++) {sumDiag1 += A[i][i];sumDiag2 += A[i][N - 1 - i];}if (sumDiag1 != target || sumDiag2 != target) {cout << "No" << endl;return 0;}cout << "Yes" << endl;return 0;
}