题解
Z字上的数字和
1 条题解
-
0
解题思路
“Z”字由哪几部分拼成?
在 n×n 的方阵里,“Z”字由三部分组成:
- 第 1 行(Z 字最上面的横);
- 第 n 行(Z 字最下面的横);
- 辅对角线(连接上面横的右端到下面横的左端的斜线,也就是从右上到左下的那条对角线)。
我们要把这三部分上所有元素加起来。
怎么不重复、不遗漏地累加?
第 1 行和第 n 行的所有格子都算,这个很简单。麻烦的是辅对角线:
- 辅对角线的最右端格子 (1, n) 已经在第 1 行里了;
- 辅对角线的最左端格子 (n, 1) 已经在第 n 行里了;
- 所以,辅对角线只需要把中间部分(第 2 行到第 n-1 行)的数加进来。
辅对角线上的格子满足:行号 + 列号 = n + 1(行、列都从 1 开始编号)。所以对第 i 行的格子,如果
i > 1 且 i < n 且 i + j == n + 1,就累加。一个容易出错的特殊情况:n = 1
当 n = 1 时,第 1 行和第 n 行是同一个格子。但这个格子既属于“Z 字上面的横”,也属于“Z 字下面的横”,所以它要被累加两次。
因此代码里要写成两个独立的 if:
if (i == 1) s += x;和if (i == n) s += x;。这样当 n = 1 时,唯一的格子会被加两次,正好正确。验证样例: n=3 时,第 1 行 0+1+2=3,第 3 行 0+1+2=3,辅对角线中间只有 (2,2) 是 1,总和 3+3+1=7,与输出一致。
参考代码
// P4509 Z字上的数字和:第1行 + 第n行 + 辅对角线中间部分 #include <iostream> using namespace std; int main() { int n, x; cin >> n; long long s = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> x; if (i == 1) s += x; // 第1行都在Z字上 if (i == n) s += x; // 第n行也在Z字上(n=1时重合也算) if (i > 1 && i < n && i + j == n + 1) s += x; // 辅对角线中间部分 } } cout << s << endl; return 0; }复杂度分析
设方阵大小是 n×n。
- 时间:两层循环要把 n×n 个格子全部读入并判断,时间复杂度是 O(n^2);
- 空间:不需要存整个方阵,边读边累加,只用几个变量,空间复杂度是 O(1)。
- 1