1050 螺旋矩阵 (25 分)
题意描述:
本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”。所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充。要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N;m≥n;且 m−n 取所有可能值中的最小值。
输入格式:
输入在第 1 行中给出一个正整数 N,第 2 行给出 N 个待填充的正整数。所有数字不超过 10^4 ,相邻数字以空格分隔。
输出格式:
输出螺旋矩阵。每行 n 个数字,共 m 行。相邻数字以 1 个空格分隔,行末不得有多余空格。
输入样例:
12
37 76 20 98 76 42 53 95 60 81 58 93
输出样例:
98 95 93
42 37 81
53 20 76
58 60 76
解题思路:
Alice: 这题真有意思,就是不好写哦,这算啥题目呢?模拟题?
Bob: 螺旋地访问数组,不对不对,原来的数组就是在内存中连续存放的。我们需要做的是在一个二维数组中合适的存放这些元素。
Alice: 就是就是,关键就是计算出对应原始数据的二维数组中每个元素的位置。比如说98在原来的数组中的下标是 0,在二维数组中对应地坐标就是 [0][0],然后 95 在原来数组中的下标是1, 在二维数组中对应地坐标就是 [0][1]…然后 93 在原来数组中的下标是2, 在二维数组中对应地坐标就是 [0][2], 然后81 在原来数组中的下标是4, 在二维数组中对应地坐标就是 [1][2]。。。
Bob: 你先别着急,从输入开始看吧,我们得首先求出来应有的行数 m 和列数n。
Alice: 然后对输入的数据从高到低排序。
Bob: 求m 和 n,我有一个想法,m 和 n尽量接近, 而且m * n == N ,m 和 n 肯定接近 N 的平方根。就从N ** 0.5 开始往下找到第一个能整除 N 的整数就是 n, 然后 N / n 就是 m。
Alice: N 是平方数的时候也满足,看起来不错哦。
Bob: hiahiahiahia…
Alice: 关于螺旋访问,我画了个图,hiahiahia。
你看横向和纵向交替,而且横向和纵向上数字每次减少一个。第一次横向的数字个数就是n, 第一次纵向的数字个数是 m - 1 , 然后每次个数减少一个,直到所有地数字都被安放在二维数组上。
Bob: 就是就是,方向可以用一个列表 [ [0, 1], [1, 0], [0, -1], [-1, 0] ] 表示 右下左上 , 然后用一个 index 指示, 每次到行列转换的时候: index = ( index + 1 ) % 4 就可以到下一个方向了。
Alice: 然后 检测 每个行列的结束可以用 计数 加上 行列状态的检查, 而且每次到了行列转换的时候还要注意重置计数和改变行列的状态。
Bob: 嗯嗯恩,应该没神码问题啦,我去写代码试试吧,万一调通了,说不定就能过呢。就像《画家和黑客》里面说的那样,有时候我们并不能在一开始就面面俱到,让我们先开始,然后再慢慢调试,这才是黑客的做法。
Alice: wa~
代码:
- Alice’s Bravo Python Version:
def main():
N = int(input())
# 接收正整数 N
data = [int(x) for x in input().split()]
# 接收输入的N个正整数
data.sort(reverse=True)
# 按照从大到小的顺序排序
n = int(N ** 0.5)
# n 是 < N ** 0.5 且能被 N 整除的第一个整数
while N % n != 0:
n -= 1
m = int(N / n)
answer = [[0 for x in range(n)] for z in range(m)]
# answer是一个二维数组,用来记录螺旋访问的结果
directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]
# directions 记录四个移动的方向,分别是右,下,左,上
direction_index = 0
# 记录当前的方向
vertical_count = m - 1
# 记录本次 竖直方向上应访问的元素个数
horizontal_count = n
# 记录本次水平方向上应访问的元素个数
vertical = False
# 是否在竖直方向上前进,否就是在水平方向上前进
count_inline = 0
# 记录当前方向上访问过的元素个数
count = 0
# 记录已经访问过的元素总个数
coorx = 0
coory = -1
# 当前坐标
while count < N:
# 直到所有的N个元素都用尽
direction = directions[direction_index]
coorx += direction[0]
coory += direction[1]
# 前进一步
answer[coorx][coory] = data[count]
# 螺旋赋值
count += 1
count_inline += 1
# 记录数都加一
if vertical and count_inline == vertical_count:
# 如果是在竖直方向上走到头了
vertical = False
# 接下来走水平方向
direction_index = (direction_index + 1) % 4
# 下一个方向
vertical_count -= 1
# 下次的竖直方向上的元素个数要减一
count_inline = 0
# 下个方向的元素个数置零
elif not vertical and count_inline == horizontal_count:
# 如果是在水平方向上走到头了
vertical = True
# 接下来走竖直方向
direction_index = (direction_index + 1) % 4
# 下一个方向
horizontal_count -= 1
# 下次的水平方向上的元素个数要减一
count_inline = 0
# 下个方向的元素个数置零
for line in answer:
print(' '.join(str(x) for x in line))
# 依次输出每行的元素
if __name__ == '__main__':
main()
易错点:
- 赠送测试样例如下 :
1
1
2
1 2
4
1 2 3 4
- (⊙o⊙)…
总结:
- Alice’s Bravo Python Version: