문제 설명
여러 개의 행렬이 주어졌을 때, 이 행렬들을 곱하는 과정에서 필요한 연산 횟수를 최소화하는 방법을 찾는 문제가 있습니다.
행렬 A의 크기가 pq
이고 행렬 B의 크기가 qr
일 때, 이 두 행렬을 곱하는 데 필요한 연산 횟수는 p * q * r
입니다.
우리는 주어진 여러 개의 행렬을 곱할 때 전체적인 곱셈 연산 횟수를 최소화하도록 행렬의 곱셈 순서를 결정해야 합니다.
문제 정의
다음과 같은 n
개의 행렬 크기가 주어질 때, 이 행렬들을 곱하는 과정에서의 최소 곱셈 연산 횟수를 구하세요.
입력
- 첫 줄에 행렬의 개수
n
(1 ≤ n ≤ 100) 이 주어집니다. - 다음
n
줄에 각각의 행렬 크기p_i × q_i
가 주어집니다.
출력
행렬을 곱하는 데 필요한 최소 연산 횟수를 출력하세요.
예제
3 10 20 20 30 30 10
3000
문제 풀이 과정
1. 기본 개념 이해
행렬 곱셈은 두 행렬의 차원에 따라 결정됩니다. 행렬 A (p×q)와 행렬 B (q×r)를 곱하면 결과는 행렬 C (p×r)가 됩니다.
이때 필요한 연산 횟수는 p * q * r
입니다. 만약 여러 개의 행렬이 주어졌을 경우, 최적의 곱셈 순서를 찾는 것이 중요합니다.
2. 동적 계획법(Dynamic Programming) 활용
이 문제는 동적 계획법을 통해 해결할 수 있습니다. 행렬 곱셈의 최적 순서를 결정하기 위해 DP 테이블을 구성할 수 있습니다.
dp[i][j]
를 i
번째 행렬부터 j
번째 행렬까지 곱할 때 필요한 최소 연산 횟수로 설정합니다.
3. DP 테이블 채우기
1. dp[i][i] = 0
(자기 자신과 곱하는 경우에는 연산이 필요하지 않으므로)
2. 두 개 이상의 행렬을 곱할 때, 중간에 있는 행렬을 기준으로 나누어 계산합니다.
3. 행렬 곱 순서는 다음과 같이 결정됩니다.
for length from 2 to n: for i from 1 to n-length+1: j = i + length - 1 dp[i][j] = ∞ for k from i to j-1: cost = dp[i][k] + dp[k+1][j] + dimensions[i-1]*dimensions[k]*dimensions[j] dp[i][j] = min(dp[i][j], cost)
4. 파이썬 구현 및 C++ 코드
위의 알고리즘을 C++로 구현해보도록 하겠습니다.
#include#include #include using namespace std; int main() { int n; cin >> n; vector dimensions(n + 1); for (int i = 0; i < n; i++) { int p, q; cin >> p >> q; dimensions[i] = p; if (i == n - 1) dimensions[i + 1] = q; // 마지막 행렬의 열 수 } vector > dp(n, vector (n, 0)); for (int length = 2; length <= n; length++) { for (int i = 0; i < n - length + 1; i++) { int j = i + length - 1; dp[i][j] = INT_MAX; for (int k = i; k < j; k++) { int cost = dp[i][k] + dp[k + 1][j] + dimensions[i] * dimensions[k + 1] * dimensions[j + 1]; dp[i][j] = min(dp[i][j], cost); } } } cout << dp[0][n - 1] << endl; return 0; }
5. 시간 복잡도
이 알고리즘의 시간 복잡도는 O(n^3)입니다. 이는 행렬의 개수가 n일 때, 모든 가능한 연산 순서를 고려해야 하므로 발생하는 복잡도입니다.
6. 결론
행렬 곱 연산의 최소화 문제는 동적 계획법을 통해 효율적으로 해결할 수 있습니다.
이 문제는 알고리즘 문제 해결 능력을 키우는 데 매우 유용하며, 다양한 분야에서 활용될 수 있는 중요한 주제입니다.
C++를 통해 이 문제를 구현해보면서 알고리즘의 개념을 더욱 깊이 이해하고, 실제 코딩 테스트에서 적용할 수 있는 능력을 기를 수 있습니다.