- 크기가 N*M인 행렬 A와 M*K인 B를 곱할 때 필요한 곱셈 연산의 수는 총 N*M*K번
- 행렬 N개의 크기가 주어졌을 때, 모든 행렬을 곱하는데 필요한 곱셉 연산 횟수의 최솟값을 구하기
이 문제는 행렬을 배우지 못한 세대인 제게는 볼 때부터 매우 두려운 문제였습니다. 하지만 문제에서 곱셈 연산의 수 공식을 알려주고 있기 때문에 그것만 이용하면 충분히 풀 수 있을 것 같습니다.(지금 생각해보면...) 유튜브 영상을 몇 번 돌려보고 같이 공부하는 팀원에게 설명도 몇 번 해보고, 친구의 도움도 받아서 겨우 이해한 내용을 작성합니다.
위 내용을 바탕으로 DP 테이블을 그려보면 아래와 같습니다.
matrix = [[]]
행렬의 정보를 담을 배열을 만들어줍니다. 이후에 인덱스를 편하게 가져오기 위해서 0번째 빈 값을 넣어줍니다.
DP = [[float("inf") for _ in range(N+1)] for _ in range(N+1)]
이후에 min값을 찾을 때 방해가 되지 않도록 무한으로 초기화합니다. 0번 행, 열을 만들기 위해 행렬 개수+1 크기의 테이블을 만듭니다.
for i in range(N+1):
DP[i][i] = 0
DP[i][i]값을 0으로 초기화시켜줍니다.
for a in range(N-1, 0, -1):
dif = N-a
for b in range(1, a+1):
for k in range(b, b+dif): # DP[b][] + DP[][b+dif] 이므로 b부터 b+dif-1까지 보고 싶음
DP[b][b+dif] = min(DP[b][b+dif], DP[b][k] + DP[k+1][b+dif] + matrix[b][0]*matrix[k][1]*matrix[b+dif][1])
3개의 for문을 돌기 때문에 인덱스를 이해하는 것이 굉장히 중요합니다!
# 행렬 곱셈 순서 - DP
import sys
N = int(sys.stdin.readline())
matrix = [[]]
for _ in range(N):
matrix.append(list(map(int, sys.stdin.readline().split())))
DP = [[float("inf") for _ in range(N+1)] for _ in range(N+1)]
for i in range(N+1):
DP[i][i] = 0
for a in range(N-1, 0, -1): ## 대각선에서 값이 들어갈 칸의 개수
dif = N-a # 각 칸의 i, j의 차이
for b in range(1, a+1): # i의 값
for k in range(b, b+dif): # DP[b][] + DP[][b+dif] 이므로 b부터 b+dif-1까지 보고 싶음
DP[b][b+dif] = min(DP[b][b+dif], DP[b][k] + DP[k+1][b+dif] + matrix[b][0]*matrix[k][1]*matrix[b+dif][1])
print(DP[1][N])