【矩阵变换】19268:旋转树塔
题目描述
小 X 是 C 城著名的考古学家。一日,他被重金聘请调查一座荒漠中的宫殿。宫殿大门紧闭,但这难不倒聪明的小X。他在隐蔽处发现了两个数字正方形:
小 X 略加思索便发现了其中的奥妙:把数字从小到大依次填入正方形中,每次填最外面的一圈;每一圈从左上角开始,按照顺时针、逆时针、顺时针……的顺序填。
作为小 X 的助手,他希望你帮助他以相同的规律填上旁边 n*n 的空白方阵。
这里方阵是数字正方形的简称,通常用二维数组来存放其中的数字。
输入
输入数据仅有一行,包含一个正整数 n,表示方阵的边长,即每行每列有多少个数。
输出
输出仅 n 行,每行 n 个正整数,相邻两数之间严格用一个空格隔开。
样例输入
6
样例输出
1 2 3 4 5 6
20 21 32 31 30 7
19 22 33 34 29 8
18 23 36 35 28 9
17 24 25 26 27 10
16 15 14 13 12 11
题解
逆时针、顺时针交替打印具有周期性,打印方向每改变4次,逆时针和顺时针打印顺序改变,周期为4。第0,2,4……等偶数周期为逆时针,第1,3,5……等奇数周期为顺时针。
解决本题关键在于是确定边界。边界应当包括:二维数组的边界、已打印数字与未打印数字的边界(按照套路定义0-1数组)。到达边界意味着打印方向的改变。设dx,dy分别为水平、垂直方向的增量,则打印方向的改变(例如由水平方向打印转变为垂直方向打印)就是水平、垂直方向的增量的互换,即swap(dx,dy),但是在每次互换增量正负交替(闭环),只要使每次交换后dy=-dy。
#include <iostream>
#include <algorithm>
using namespace std;
int n;
int a[50][50], b[50][50];//b:构造0-1数组
int main() {
cin >> n;
int x = 0, y = 0, dx = 0, dy = 1, cnt = 0;
for (int i = 1; i <= n * n; i++) {
if (cnt / 4 & 1) a[y][x] = i;//如果周期为奇数,则顺时针打印
else a[x][y] = i;//如果周期为偶数,则逆时针打印
//&为按位与运算符,奇数最低位为1,n&1=1,偶数最低位为0,n&1=0;
b[x][y] = 1;
int xx = x + dx, yy = y + dy;
//定义xx,yy是趋势量,预测是否需要改变打印方向
if (xx < 0 || yy < 0 || xx >= n || yy >= n || b[xx][yy]) {
//判断是否到达边界
swap(dx, dy);
dy = -dy;
cnt++; //方向改变次数加一
}
x += dx;
y += dy;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << a[i][j] << " ";
}
cout << endl;
}
return 0;
}
笔者的C语言课程也出现了一道类似的作业题。
这一题较上一题相比,思路几乎相同,而且只有逆时针打印,简单一些。
#include <cstdio>
#include <algorithm>
using namespace std;
int a[10][10], b[10][10];
int main() {
int n;
scanf("%d", &n);
int x = 0, y = 0, dx = 0, dy = 1;
for (int i = 1; i <= n * n; i++) {
a[x][y] = i;
b[x][y] = 1;
int xx = x + dx;
int yy = y + dy;
if (xx < 0 || yy < 0 || xx >= n || yy >= n || b[xx][yy]) {
swap(dx, dy);
dy = -dy;
}
x += dx;
y += dy;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf("%5d", a[i][j]);
}
printf("\n");
}
}