题目

所谓“螺旋方阵”,是指对任意给定的N,将1到N×N的数字从左上角第1个格子开始,按顺时针螺旋方向顺序填入N×N的方阵里。本题要求构造这样的螺旋方阵。

输入格式:

输入在一行中给出一个正整数N(<=30)。

输出格式:

输出N×N的螺旋方阵。每行N个数字,每个数字占3位。

输入样例:

1
5

输出样例:

1
2
3
4
5
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009

输入样例:

1
10

输出样例:

1
2
3
4
5
6
7
8
9
10
001 002 003 004 005 006 007 008 009 010
036 037 038 039 040 041 042 043 044 011
035 064 065 066 067 068 069 070 045 012
034 063 084 085 086 087 088 071 046 013
033 062 083 096 097 098 089 072 047 014
032 061 082 095 100 099 090 073 048 015
031 060 081 094 093 092 091 074 049 016
030 059 080 079 078 077 076 075 050 017
029 058 057 056 055 054 053 052 051 018
028 027 026 025 024 023 022 021 020 019

简单分析

以输入5为例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009

第一圈开始,每一步四笔,也就是步长为4
第一步:(0,0)起点
001 002 003 004
第二步:(0,4)起点
001 002 003 004 005
006
007
008

第三步:(4,4)起点
001 002 003 004 005
006
007
008
012 011 010 009
第四步:(4,0)起点
001 002 003 004 005
016 006
015 007
014 008
013 012 011 010 009
第一圈结束

第二圈开始,步长为2
第一步:(1,1)起点
001 002 003 004 005
016 017 018 006
015 007
014 008
013 012 011 010 009
第二步:(1,3)起点
001 002 003 004 005
016 017 018 019 006
015 020 007
014 008
013 012 011 010 009
第三步:(3,3)起点
001 002 003 004 005
016 017 018 019 006
015 020 007
014 022 021 008
013 012 011 010 009
第四步:(1,3)起点
001 002 003 004 005
016 017 018 019 006
015 024 020 007
014 023 022 021 008
013 012 011 010 009
第二圈结束

第三圈开始,步长为1
第一步:
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009
第二步:
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009
第三步:
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009
第四步:
001 002 003 004 005
016 017 018 019 006
015 024 025 020 007
014 023 022 021 008
013 012 011 010 009
第三圈结束

以6为例子

001 002 003 004 005 006

020 021 022 023 024 007

019 032 033 034 025 008

018 031 036 035 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第一圈开始,每一步五笔,也就是步长为5

第一步:(0,0)起点

001 002 003 004 005

第二步:(0,5)起点

001 002 003 004 005 006

               007

               008

               009

               010
         
     

第三步:(5,5)起点

001 002 003 004 005 006

               007

               008

               009

               010

 015 014 013 012 011

第四步:(5,0)起点

001 002 003 004 005 006

020 007

019 008

018 009

017 010

016 015 014 013 012 011

第一圈结束

第二圈开始,步长为3

第一步:(1,1)起点

001 002 003 004 005 006

020 021 022 023 007

019 008

018 009

017 010

016 015 014 013 012 011

第二步:(1,4)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 025 008

018 026 009

017 010

016 015 014 013 012 011

第三步:(4,4)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 025 008

018 026 009

017 029 028 027 010

016 015 014 013 012 011

第四步:(4,1)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 032 025 008

018 031 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第二圈结束

第三圈开始,步长为1

第一步:(2,2)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 032 033 025 008

018 031 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第二步:(2,3)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 032 033 034 025 008

018 031 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第三步:(3,3)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 032 033 034 025 008

018 031 035 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第四步:(3,2)起点

001 002 003 004 005 006

020 021 022 023 024 007

019 032 033 034 025 008

018 031 036 035 026 009

017 030 029 028 027 010

016 015 014 013 012 011

第三圈结束

从上面可以看到四步一个圈,那就只需要确定圈数,步长,起点即可

那现在可以大体把代码格式写出来了

1
2
3
4
5
6
7
8
9
10
11
int count = 1;//填空格时候计数的
int map[n][n];
memset(map, 0, sizeof(map));
int length;//步长
for (int cycle = 0; cycle < 圈数; cycle++) {
length=确定这一圈的步长
第一步→
第二步↓
第三步←
第四步↑
}

确定圈数:

先看圈数55和66都是三圈,那么 圈数 就是

1
(n % 2 == 0 ? n : n + 1) / 2

确定步长:

从5*5中可以看到步长是4,2,1

4,2很好确定关系,减了2。2,1就不好确定关系了

先不管,再来看下6*6是什么情况

从5*5中可以看到步长是5,3,1

这个就很好,都是减了2,那5*5最后一圈步长为1的就是特殊了

那么步长公式就是

1
n - 2 * cycle - 1

这时候再回过头来看下刚刚的特殊情况这个步长是多少,

当cycle走到最后一圈的时候,即cycle=2(cycle取值是 第0圈,第1圈,第2圈)

1
5 - 2 * 2 - 1

步长等于0,那按我们写的代码模板,就需要后面的四步一步都不执行,所以我们在第一步之前判断一下length就好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int count = 1;//填空格时候计数的
int map[n][n];
memset(map, 0, sizeof(map));
int length;//步长
for (int cycle = 0; cycle < 圈数; cycle++) {
length=确定这一圈的步长
if (length == 0) {
直接确定中间数字
break;
}
第一步→
第二步↓
第三步←
第四步↑
}

确定起点:

每一圈一共四步,那一共有四个起点

以6*6为例

每次第一步的坐标分别为(0,0),(1,1),(2,2),注:(横,纵)

001 002 003 004 005 006
020 021 022 023 024 007
019 032 033 034 025 008
018 031 036 035 026 009
017 030 029 028 027 010
016 015 014 013 012 011

那坐标和圈数的关系,由此可以判断坐标为(cycle,cycle)

每次第二步的坐标分别为(0,5),(1,4),(2,3),注:(横,纵)

001 002 003 004 005 006
020 021 022 023 024 007
019 032 033 034 025 008
018 031 036 035 026 009
017 030 029 028 027 010
016 015 014 013 012 011

那坐标和圈数的关系,由此可以判断坐标为(cycle,n-1-cycle)

每次第三步的坐标分别为(5,5),(4,4),(3,3),注:(横,纵)

001 002 003 004 005 006
020 021 022 023 024 007
019 032 033 034 025 008
018 031 036 035 026 009
017 030 029 028 027 010
016 015 014 013 012 011

那坐标和圈数的关系,由此可以判断坐标为(n-1-cycle,n-1-cycle)

每次第四步的坐标分别为(0,5),(1,4),(2,3),注:(横,纵)

001 002 003 004 005 006
020 021 022 023 024 007
019 032 033 034 025 008
018 031 036 035 026 009
017 030 029 028 027 010
016 015 014 013 012 011

那坐标和圈数的关系,由此可以判断坐标为(cycle,n-1-cycle)


到此为止就可以把刚刚的代码模板补全了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int count = 1;//填空格时候计数的
int map[n][n];
memset(map, 0, sizeof(map));
int length;//步长
for (int cycle = 0; cycle < (n % 2 == 0 ? n : n + 1) / 2; cycle++) {
length = n - 2 * cycle - 1;
if (length == 0) {
map[n / 2][n / 2] = count++;
//这种情况的话肯定就是奇数,n/2一定就是中间那个,小数直接扔掉了
break;
}
for (int pos = cycle, cnt = 0; cnt < length; ++cnt) {
map[cycle][pos++/*右移*/] = count++;
}

for (int pos = cycle, cnt = 0; cnt < length; ++cnt) {
map[pos++/*下移*/][n - 1 - cycle] = count++;
}

for (int pos = n - 1 - cycle, cnt = 0; cnt < length; ++cnt) {
map[n - 1 - cycle][pos--/*左移*/] = count++;
}

for (int pos = n - 1 - cycle, cnt = 0; cnt < length; ++cnt) {
map[pos--/*上移*/][cycle] = count++;
}
}

之后就是打印整个数组了


AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <cstdio>
#include <cstring>
#include "iostream"
#include "memory"

using namespace std;

int main() {

int n;
cin >> n;

int count = 1;//填空格时候计数的
int map[n][n];
memset(map, 0, sizeof(map));
int length;//步长
for (int cycle = 0; cycle < (n % 2 == 0 ? n : n + 1) / 2; cycle++) {
length = n - 2 * cycle - 1;
if (length == 0) {
map[n / 2][n / 2] = count++;
//这种情况的话肯定就是奇数,n/2一定就是中间那个,小数直接扔掉了
break;
}
for (int pos = cycle, cnt = 0; cnt < length; ++cnt) {
map[cycle][pos++/*右移*/] = count++;
}

for (int pos = cycle, cnt = 0; cnt < length; ++cnt) {
map[pos++/*下移*/][n - 1 - cycle] = count++;
}

for (int pos = n - 1 - cycle, cnt = 0; cnt < length; ++cnt) {
map[n - 1 - cycle][pos--/*左移*/] = count++;
}

for (int pos = n - 1 - cycle, cnt = 0; cnt < length; ++cnt) {
map[pos--/*上移*/][cycle] = count++;
}
}

for (int i = 0; i < n; i++) {
if (i != 0) {
cout << endl;
}
for (int j = 0; j < n; j++) {
if (j != 0) {
cout << ' ';
}
printf("%03d", map[i][j]);
}
}
return 0;
}