이번 문제는 최적의 행렬 곱셈 문제이다.
기본적으로 행렬의 곱셈 성립 조건의 A(m x n)의 열의 길이와 B(n x p)의 행의 길이가 같을 때에만 성립 가능하다.
그리고 연산 후 생성된 행렬 AB는 m x p 의 길이를 가진다.
그리고 새로운 행렬 C(p x l ) 과 연산하게 되면 최종적으로 행렬 ABC 는 m x l 의 길이를 가진다.
그리고 이대 연산의 횟수는 A x B = m x n x p 이며, AB x C = m x p x l 의 연산 횟수를 거치게 된다.
이를 수학적으로 더 표현하면 m x p x (n + l) 이 된다.
위 예제를 통해 다시 설명을 되집어 보면
A (5 x 3), B(3 x 10) C (10 x 6) 이 있으며, 여기서 m, n , p , l 이 되는 값들은 각 5, 3, 10, 6 이다.
그리고 새롭게 만들어진 행렬 D 가 가능한 조합을 찾아보면, AB (5 x 10), BC(3 x 6 ) 두가지가 나온다.
따라서 5, 10 또는 3,6 이 m, p 가 되며 이때 값이 작은 3,6을 곱한다음 남은 5,10의 합을 곱한 270이 최소 연산 횟수가 된다.
한가지 문제는 전달받은 행렬의 개수는 3이상 200이하라는 것이다.
200개의 행렬의 곱셈을 시행하면서 최소 곱셈의 수를 찾아야 한다.
이 문제에서 생각해야할 부분은 총 2가지 이다.
1. 가장 연산 회수가 적은 행렬의 곱셈을 찾는 것!
2. 최종적으로 모든 행렬의 연산 곱셈이 가능한 방법을 찾는것.
다시 예를 들어서 [9, 10], [10, 9], [9, 1], [1, 2] 4개의 행렬을 계산한다고 가정해 보자. (편의상 A,B,C,D)
A = A*B[9*10*9], B*A[10*9*10]
B = B*C[10*9*1]
C = C*D[9*1*2]
각 행렬이 중복으로 들어가는걸 제외하면 4가지 행렬이 새로 만들어 진다.
그리고 다시 확인해 보면
AB([9,9] = AB*C [9*9*1]
BA[10,10] = X
BC[10,1] = A*BC[9*10*1], BC*D[10*1*2]
CD[9,2] = B*CD[10*9*2]
총 4개의 행렬이 만들어진다.
그리고 최종적으로 모든 행렬의 곱셈이 가능한 조합을 확인해보면
ABC[9,1] = ABC*D = [9*1*2]
ABC[9,1] = ABC*D = [9*1*2]
BCD[10,2] = A*BCD = [9*10*2]
총 3가지 값이 나오게 된다.
여기서 형태를 보면 최종적으로 ABCD 또는 BACD 형태이며, 이 때 계산한 순서에 따라
시작 AB(810) + AB*C(81) + ABC*D(18) = 909
시작 BC(90) + A*BC(90) + ABC*D(18) = 198
시작 BC(90) + BC*D(20) + A*BCD(180) = 290
시작 CD(18) + B*CD(180) + A*BCD(180) = 378
5가지 값이 나오게 되고, 최종적으로 198이 최소 연산 횟수가 된다.
위 연산에서 알 수 있듯이 연산이 가능한 배열이 주어졌을때 순서에 상관없이 서로 인접한 행렬끼리 계산만 진행하면 모든 행렬의 연산을 시행 할 수 있다. 즉 입접한 행렬만 확인해 주면 된다.
먼저 2차원 dp 배열을 만들어 주고, 값은 최대값(math.inf) 또는 임의의 큰 값으로 설정해 주고 시작한다.
그리고 같은 행렬끼리는 곱할 수 없기 때문에 (i,i) 위치는 모두 0으로 바꿔주고 시작한다.
i의 시작값은 1 이고, j의 시작값은 0 이다.그리고 끝나는 지점 end 의 값은 i+j 가 된다.
만약 end 값이 전체 배열의 길이를 벗어난 경우라면 연산이 불가하기에 break로 해당 j 에 대한 탐색을 종료하게 된다.
예를들어 i 가 1이고, j 가 2라면 end 는 3이 된다.
그리고 다시 k 는 (1.3 ) 범위를 반복하며 값을 가지며, 이때 dp[2][[3] 의 값을 찾게 된다.
여기서 m[k] 는 한번 연산된 행렬의 마지막 값이고, j 는 시작 행렬의 첫번째 값, m[end]는 마지막 행렬의 끝 값이다.
다시 말해 A(a*b), B(b*c), C(c*d), D(d*e)라고 가정하고 BC 를 기준으로 ABC를 계산한다고 가정하면
BC 는 b*d 배열이고 A*BC 는 a*b*d 이다. 이때 b의 위치를 연산된 행렬의 첫값으로 보고 계산하는 것이다.
행렬이 5개 이고, E(e*f)가 추가되었다면?
BCD 는 b*e 배열을 가지게 되고, BCD*E 라면 시작값은 B[0] 중간값은 D[1] 끝값은 E[1]디 된다.
구글링을 통해 해결하긴 했지만, 시작할 때 접근법은 좋았던 문제이다.
다만 코드로 구현하는데 생각보다 너무 오래 걸려서 구글링의 도움을 받았는데, 다음에는 좀 더 직관적인 코드를 작성해 봐야 할것 같다.
'프로그래머스 퀴즈(Python) > level 3' 카테고리의 다른 글
23.02.28 파이썬 코딩 퀴즈#175 기지국 설치(프로그래머스 스쿨) (0) | 2023.02.28 |
---|---|
23.02.28 파이썬 코딩 퀴즈#174 스티커 모으기(2)(프로그래머스 스쿨) (0) | 2023.02.28 |
23.02.24 파이썬 코딩 퀴즈#172 최고의 집합(프로그래머스 스쿨) (0) | 2023.02.24 |
23.02.24 파이썬 코딩 퀴즈#171 야근 지수 (프로그래머스 스쿨) (0) | 2023.02.24 |
23.02.24 파이썬 코딩 퀴즈#170 선입 선출 스케줄링 (프로그래머스 스쿨) (0) | 2023.02.24 |