https://www.acmicpc.net/problem/11049
그냥 DP인줄 알았는데
행렬 곱 최소 비용 문제는
- 구간 범위
- 쪼개서 비교를 하고
- 최소비용을 계속 갱신
해나가는 것이 핵심이다.
자를 수 있는 한 최대한 범위를 자르고, 작은 해부터 최적의 해를 알아가는 것인데,
해외 검색 키워드로는 Matrix Chain Multiplication 이 있다.
아무 곳에서 잘라서, 왼쪽 오른쪽 그룹을 고려하게 되면 그룹이 더 나눠질 수 없는 상황까지 줄인 다음, 거기서부터 값을 채워나가는 형태를 생각하게 된다. 이게 전형적인 Bottom Up방식으로 피티 지는 설명한다.
dp[i][j] = min(
dp[i][k] + dp[k+1][j] + (i~k 행렬) * (k+1~j 행렬) 곱셈비용
) for 모든 k in [i, j-1]
범위 i j를 정의하고 자를 구간 k를 갱신해 나가면서 dp 표를 완성해 나가는 방식인데, 이 k는 결국에 한 번 자름으로써 2개의 구역이 만들어 지니 그 2개 구역에서의 곱셈을 진행하는데 있어 필요한 매개체 역할도 수행하게 된다.
그러면 i*k k*j? 뭐 조금 기호는 다를 수 있겠지만, 여기서 발생하는 곱셈 비용까지 고려한다면 비교 하기전 해야할 계산은 다 끝난 셈이다.
그래서 해당 아이디어를 가능한 반영한 채로 작성된 코드를 이렇게 정리 할 수 있었다.
import sys
input = sys.stdin.readline
caseCnt = int(input())
caseList = [0]
dp = [[float('inf')] * (caseCnt + 1) for _ in range(caseCnt + 1)]
for i in range(caseCnt):
matX, matY = map(int, input().split())
caseList.append([matX, matY])
for i in range(1, caseCnt + 1):
dp[i][i] = 0
for length in range(2, caseCnt + 1):
for i in range(1, caseCnt - length + 2):
j = i + length - 1
for k in range(i, j):
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + caseList[i][0] * caseList[k][1] * caseList[j][1])
print(dp[1][caseCnt])
이거 PyPy3로 해야한다. 씨
'문제풀이' 카테고리의 다른 글
[PY] 1946 : 신입사원 (0) | 2025.04.09 |
---|---|
[PY] 1541 : 잃어버린 괄호 (1) | 2025.04.09 |
[PY] 12865 : 평범한 배낭 (0) | 2025.04.06 |
[PY] 11047 : 동전 0 (1) | 2025.04.05 |
[PY] 2748 : 피보나치 수 2 (0) | 2025.04.05 |