1050 螺旋矩阵 (25 分)

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:
    result
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值