https://www.acmicpc.net/problem/11049
이전에 풀이했던 파일 합치기 문제와 유사하다. 해당 글의 링크는 아래에.
행렬 곱은 결합 법칙은 성립, 교환 법칙은 성립하지 않는다. 따라서 바로 옆에 있는 행렬끼리 곱셈 연산이 가능하다. 다시말해, 연속된 두 행렬 간 곱셈만이 가능하다.
n개의 행렬에 대해 생각해보면, 아래와 같다. 하나의 문제가 두개의 더 작은 문제로 구성되어 있는 것을 알 수 있다(재귀 피보나치와 유사). 재귀를 통해서 브루트포스로 접근하면 O(2^n) 일 것으로 보인다. 따라서 불가능하다.
(1번째) (곱셈) (2번째 부터 n번째 까지의 곱셈의 결과)
(1번째 부터 2번째 까지의 곱셈의 결과) (곱셈) (3번째 부터 n번째 까지의 곱셈의 결과)
...
...
...
(1번째 부터 n-1번째 까지의 곱셈의 결과) (곱셈) (n번째)
그렇다면 작은 문제들을 memo 해놓고, 큰 문제를 구하는데 사용할 수 있다. 다이나믹 프로그래밍이다. 그렇다면 이제 점화식을 구해야하는데, 바로 위의 식에서 이미 그 형태가 나와있는 것을 알 수 있다.
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
int matrixes[500][2], dp[500][500];
void go() {
fill_n(dp[0], 500 * 500, INT32_MAX);
for (int i = 0; i < n; i++) {
dp[i][i] = 0;
}
for (int len = 1; len <= n; len++) {
for (int left = 0; left + len < n; left++) {
int right = left + len;
for (int curIdx = left; curIdx < right; curIdx++) {
dp[left][right] = min(dp[left][right], matrixes[left][0] * matrixes[curIdx][1] * matrixes[right][1] + dp[left][curIdx] + dp[curIdx + 1][right]);
}
}
}
cout << dp[0][n - 1];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> n;
for (int i = 0; i < n; i++) {
cin >> matrixes[i][0] >> matrixes[i][1];
}
go();
return 0;
}