20x20 행렬에서 4개씩 가로, 세로, 대각선 방향으로 연속한 숫자들의 곱을 계산하여 그 중 최대값을 찾는다.
파이썬의 경우, 긴 1차원 배열로 취급하여 특정 좌표에서 가로, 세로, 대각선에 위치한 원소를 추출하는 방식으로 계산했으나, 줄리아는 20x20 행렬로 보고, 부분행렬의 가능한 모든 곱을 찾는 방법을 사용해본다. (이쪽이 훨씬 더 깔끔하다.)
먼저 문자열을 모두 split()
한 다음 정수로 변환한다. 400개짜리 배열이 만들어질 것이다. 문자열을 정수나 실수등 다른 값 타입으로 변환할 때에는 parse()
를 사용한다. 예를 들어 정수를 표현한 문자열을 정수로 변환하려면 다음과 같이 한다.
v = "123"
i = parse(Integer, v)
람다식을 사용해서 맵핑할 수 있는데, .|>
을 사용해서 좀 더 간단히 표현할 수 있다.
s = """08 02 22 .... """
xs = s |> split .|> x -> parse(Integer, x)
이렇게 변환한 배열을 2차원 배열로 만들어보자. 줄리아의 배열은 열방향이 우선이므로 문제와 같은 행방향 우선 배열로 만들려면 전치해야 한다. reshape()
한 다음에 전치하자. 전치는 transpose()
함수도 있지만, T'
와 같이 간단히 표현하여 만들 수 있다.
xs = reshape(xs, 20, 20)'
첫번째 값인 08을 기준으로 4x4 행렬을 생각해보자. 여기서 찾을 수 있는 가능한 곱은 다음과 같다.
- 행방향의 4개의 숫자의 각각의 곱
- 열방향의 4개의 숫자의 각각의 곱
- 오른쪽 아래 방향의 대각선의 곱
- 왼쪽 아래 방향 대각선의 곱
행, 열 방향의 곱은 prod
함수를 해당 방향으로 맵핑하면 된다. 다차원행렬에서 특정한 축방향으로 각각의 슬라이스를 맵핑하는 것은 mapslices()
함수를 사용한다. 열방향 각각의 곱을 찾아보자
ys = xs[1:4, 1:4]
mapslices(prod, ys, dims=1)
#1×4 Matrix{Int64}:
# 1651104 336140 6414210 6514520
mapslices(prod, ys, dims=2)
#4×1 Matrix{Int64}:
# 34144
# 9507960
# 8981847
# 7953400
대각선의 경우 ys[i:i] for i=1:4
와 같은 표현을 써도 되지만, diag()
함수를 써서 대각선의 원소를 추려낼 수 있다. 단, 해당 함수는 LinearAlgebra
모듈을 사용해야 한다. 쓰는 것이 간편하니까 해보자.
using LinearAlgegra
ys |> diag |> prod
# 279496
반대쪽 대각선은 행렬을 90도로 왼쪽으로 돌려서 diag()
를 적용하면 된다. 회전 변환은 rotl90
으로 할 수 있다. 이상의 내용을 조합하여 정리하면 다음과 같다.
using LinearAlgebra
s = """08 02 22 97 38 15 00 40 00 75 04 .... """ # 문제의 텍스트를 붙여넣기
# 텍스트를 20x20 행렬로 변환
xs = s |> split .|> (x -> parse(Int, x))
xs = reshape(xs, 20, 20)'
# (1,1) ... (17, 17)에서 가능한 모든 방향의 곱을 계산하고 최대값을 취함
# 그 중에서 다시 최대값을 취해출력
@time begin
map((a, b) for a=1:17,b=1:17) do (a, b)
ys = xs[a:a+3,b:b+3]
map(mapslices(prod, ys, dims=1) |> maximum,
mapslices(prod, ys, dims=2) |> maximum,
ys |> diag |> prod,
ys |> rotl90 |> diag |> prod)
end |> maximum |> println
end