Cプログラミング
 Computer >> コンピューター >  >> プログラミング >> Cプログラミング

行列連鎖乗積問題をC言語で解く方法|動的計画法による最小乗算回数の求め方

この記事では、行列(マトリックス)の列(配列)が与えられたときに、行列連鎖乗積(Matrix Chain Multiplication)を効率的に計算するCプログラムを紹介します。目的は、必要な乗算の回数が最小になるように、行列を掛ける順序を見つけることです。

行列の次元は、n個の要素を持つ配列 arr[] によって定義され、i番目の行列のサイズは arr[i-1] × arr[i] として表されます。

問題例で理解しよう

入力

array[] = {3, 4, 5, 6}

出力

150

解説

この場合、各行列のサイズは以下のようになります。

Mat1 = 3×4, Mat2 = 4×5, Mat3 = 5×6

これら3つの行列を掛ける順序には、次の2通りがあります。

mat1*(mat2*mat3) → (3*4*6) + (4*5*6) = 72 + 120 = 192
(mat1*mat2)*mat3 → (3*4*5) + (3*5*6) = 60 + 90 = 150

掛ける順序によって必要な乗算回数が変わることがわかります。この例では、(mat1*mat2)*mat3 の順序で掛けた場合の 150回 が最小となります。

動的計画法によるアプローチ

この問題は、動的計画法(Dynamic Programming)を使って効率的に解くことができます。なぜなら、この問題は動的計画法が適用できる2つの重要な性質、すなわち最適部分構造(optimal substructure)重複する部分問題(overlapping subproblems)を満たしているからです。

具体的には、行列の連鎖をさまざまな位置で分割し、それぞれの分割における最小コストを表 minMul[][] に記録しながら、全体の最小コストを段階的に求めていきます。一度計算した部分問題の結果を保存して再利用することで、同じ計算を繰り返す無駄を省いています。

Cプログラム:動的計画法による行列連鎖乗積

サンプルコード

#include <stdio.h>
int MatrixChainMultuplication(int arr[], int n) {
    int minMul[n][n];
    int j, q;
    for (int i = 1; i < n; i++)
        minMul[i][i] = 0;
    for (int L = 2; L < n; L++) {
        for (int i = 1; i < n - L + 1; i++) {
            j = i + L - 1;
            minMul[i][j] = 99999999;
            for (int k = i; k <= j - 1; k++) {
                q = minMul[i][k] + minMul[k + 1][j] + arr[i - 1] * arr[k] * arr[j];
                if (q < minMul[i][j])
                    minMul[i][j] = q;
            }
        }
    }
    return minMul[1][n - 1];
}
int main(){
    int arr[] = {3, 4, 5, 6, 7, 8};
    int size = sizeof(arr) / sizeof(arr[0]);
    printf("Minimum number of multiplications required for the matrices multiplication is %d ", MatrixChainMultuplication(arr, size));
    getchar();
    return 0;
}

実行結果

Minimum number of multiplications required for the matrices multiplication is 444

このプログラムでは、6つの要素 {3, 4, 5, 6, 7, 8} を持つ配列から5つの行列(3×4、4×5、5×6、6×7、7×8)を生成し、それらを掛ける際の最小乗算回数である 444 を出力しています。

このアルゴリズムの計算量は O(n³)、必要なメモリは O(n²) です。すべての掛け順を網羅的に試す総当たり法(指数時間かかる)と比べて、大幅に高速に最適解を求められる点が大きなメリットです。

  1. 【初心者向け】長方形の面積と外周を求めるC言語プログラムの書き方

    長方形の「長さ」と「幅」が与えられたとき、その面積と外周(周囲の長さ)を計算する方法を、C言語のサンプルコード付きでわかりやすく解説します。 長方形とは? 長方形とは、4つの辺と4つの直角(90度)を持つ2次元の図形です。長方形では、隣り合う辺の長さは異なりますが、向かい合う辺どうしは必ず同じ長さになります。また、2本の対角線も互いに等しい長さを持ちます。 下の図は長方形を模式的に表したものです。 ここで、Aは長方形の幅(breadth)、Bは長さ(length)を表しています。 面積と外周の計算式 面積の公式 長方形の面積は、次の式で求められます。 面積 = 長さ × 幅 外周の公式

  2. 配列の全要素を乗算するC++プログラムの解説

    整数型の要素を持つ配列が与えられたとき、配列内のすべての要素を掛け合わせ、その積を表示することを考えます。本記事では、この問題をC++(C言語スタイルのコード)で解く方法を、アプローチ、アルゴリズム、サンプルコード、実行結果まで順を追って解説します。 例 入力: arr[]={1,2,3,4,5,6,7} 出力: 1 x 2 x 3 x 4 x 5 x 6 x 7 = 5040 入力: arr[]={3, 4, 6, 2, 7, 8, 4} 出力: 3 x 4 x 6 x 2 x 7 x 8 x 4 = 32256 解き方のアプローチ この問題は、累積用の一時変数を用意し、配列の要素を先頭