Функциональный алгоритм (ну, почти):
def printMatrix(matrix):
print(*(" ".join(map(lambda i: "%3d" % i, row)) for row in matrix), sep = '\n')
N, M = map(int, input("Размерность матрицы через пробел: ").split())
D = N + M - 1 # кол-во диагоналей
mnn, mxn = (N, M) if N < M else (M, N)
matrix = [[0] * M for _ in range(N)]
def diagLen(d): # длина диагонали с номером d
return d + 1 if d < mnn else mnn if d < mxn else D - d
def diagLensUpTo(d): # сумма длин диагоналей с номерами от 0 до d, не включая d
prog = min(d, mnn - 1) # кол-во возрастающих диагоналей
const = min(mxn, d) - prog # кол-во константных диагоналей
reg = max(d - prog - const, 0) # кол-во убывающих диагоналей
return prog * (prog + 1) // 2 + const * mnn + (mnn * (mnn - 1) - (mnn - 1 - reg) * (mnn - reg)) // 2
def snakeElem(i, j):
d = i + j # номер диагонали
vad = 0 if d < N else N - d - 1 # вертикальная поправка
return diagLensUpTo(d) + (j + 1 + vad if d % 2 else diagLen(d) - j - vad)
printMatrix([[snakeElem(i, j) for j in range(M)] for i in range(N)])
Значение каждого элемента вычисляется на основе его индексов и суммы длин предыдущих диагоналей. Используется такое понятие, как номер диагонали (это сумма индексов). Номер диагонали, длина диагонали и сумма предшествующих длин рассчитываются за константное время, а общая сложность алгоритма - линейная (O(N * M)). Матрица заполняется пробегом по строкам и элементам каждой строки, причём, порядок заполнения не влияет на результат.Императивный алгоритм:
def printMatrix(matrix):
print(*(" ".join(map(lambda i: "%3d" % i, row)) for row in matrix), sep = '\n')
N, M = map(int, input("Размерность матрицы через пробел: ").split())
D = N + M - 1 # кол-во диагоналей
mnn, mxn = (N, M) if N < M else (M, N)
matrix = [[0] * M for _ in range(N)]
def diagLen(d): # длина диагонали с номером d
return d + 1 if d < mnn else mnn if d < mxn else D - d
seq = 1
for d in range(D): # цикл по диагоналям
dl = diagLen(d)
vad = 0 if d < N else N - d - 1 # вертикальная поправка
for j in range(dl): # цикл по элементам диагонали
matrix[d - j + vad][j - vad] = seq + (j if d % 2 else dl - j - 1)
seq += dl
printMatrix(matrix)
В императивной версии матрица заполняется по диагоналям (i - счётчик диагоналей с 0, j - индекс элемента внутри диагонали). Нечётные диагонали заполняются в прямом порядке, чётные - в обратном. Используется сквозной счётчик (seq), из-за чего алгоритм жёстко привязан к порядку итерирования, и распараллелить его в случае чего не получится. Сложность - та же, что у функциональной версии (O(N * M)).Примеры:
1 3 4
2 5 8
6 7 9
1 3 4 9
2 5 8 10
6 7 11 12
1 3 4 10 11 18 19 26 27 34 35 42 43 50 51 58 59 66 67 74
2 5 9 12 17 20 25 28 33 36 41 44 49 52 57 60 65 68 73 75
6 8 13 16 21 24 29 32 37 40 45 48 53 56 61 64 69 72 76 79
7 14 15 22 23 30 31 38 39 46 47 54 55 62 63 70 71 77 78 80
1 3 4 10
2 5 9 11
6 8 12 17
7 13 16 18
14 15 19 20