在图像编码的算法中,需要将一个给定的方形矩阵进行 Z Z Z 字形扫描 ( Z i g z a g S c a n ) (Zigzag Scan) (ZigzagScan)。
给定一个
n
×
n
n×n
n×n 的矩阵,
Z
Z
Z 字形扫描的过程如下图所示:
对于下面的
4
×
4
4×4
4×4 的矩阵,
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
对其进行 Z Z Z 字形扫描后得到长度为 16 16 16 的序列: 1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3 1\quad5\quad 3\quad 9\quad 7\quad 3 \quad9\quad 5\quad 4\quad 7\quad 3\quad 6\quad 6 \quad4\quad 1\quad 3 1539739547366413。
请实现一个 Z Z Z 字形扫描的程序,给定一个 n × n n×n n×n 的矩阵,输出对这个矩阵进行 Z Z Z 字形扫描的结果。
输入格式
输入的第一行包含一个整数
n
n
n,表示矩阵的大小。
输入的第二行到第 n + 1 n+1 n+1 行每行包含 n n n 个正整数,由空格分隔,表示给定的矩阵。
输出格式
输出一行,包含
n
×
n
n×n
n×n 个整数,由空格分隔,表示输入的矩阵经过
Z
Z
Z 字形扫描后的结果。
数据范围
1
≤
n
≤
500
1\leq n \leq 500
1≤n≤500,
矩阵元素为不超过
1000
1000
1000 的正整数。
输入样例:
4
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3
输出样例:
1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3
(相当于遍历了邻接表数组,里边存的边数总和为
n
2
n^2
n2,所以是
O
(
n
2
)
O(n^2)
O(n2)的级别)
假设下标从
1
1
1开始,可以找到一个规律.就是说,它的输出路线是 下标之和为
2
2
2的点 下标之和为
3
3
3的点 下标之和为
4
4
4的点…
唯一要注意的地方就是说,下标之和为 3 、 5 3、5 3、5等奇数的点的路线是按照行的升序(或者我们可以称之为按输入顺序,下面会提.);而下标之和为 2 、 4 2、4 2、4等偶数的路线则按照行的降序(或者说按输入顺序,反向输出).
我直接想到的是用邻接表,但是邻接表从倒着输出不方便,干脆用 v e c t o r vector vector来代替好了,费点空间能过就行,开一个 v e c t o r vector vector数组,或者二维 v e c t o r vector vector,姑且称之为 a d j adj adj.
所以输入时,将 a [ i ] [ j ] a[i][j] a[i][j]插入到 a d j [ i + j ] adj[i+j] adj[i+j]中,就跟插入邻接表似的,就是按照输入顺序了.如上文提到的,输入顺序是行升序.所以奇数的正序输出 a d j [ k ] adj[k] adj[k]存放的元素,偶数的则倒序输出即可.
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n;
vector<int>a[maxn];
int main() {
scanf("%d", &n);
for (int i = 1, x; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &x);
a[i + j].push_back(x);
}
}
for (int i = 2; i <= n * 2; i++) {
if (i & 1) {
for (auto &it:a[i]) {
printf("%d ", it);
}
} else {
for (int j = a[i].size() - 1; j >= 0; j--) {
printf("%d ", a[i][j]);
}
}
}
return 0;
}