C++ 코딩테스트 강좌, 행렬 곱 연산 횟수의 최솟값 구하기

문제 설명

여러 개의 행렬이 주어졌을 때, 이 행렬들을 곱하는 과정에서 필요한 연산 횟수를 최소화하는 방법을 찾는 문제가 있습니다.
행렬 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++를 통해 이 문제를 구현해보면서 알고리즘의 개념을 더욱 깊이 이해하고, 실제 코딩 테스트에서 적용할 수 있는 능력을 기를 수 있습니다.

7. 참고 자료