AIZU ONLINE JUDGE

AOJ ITP1 7_D(Matrix Multiplication)を解く

AOJ_ITP1_7_D

Aizu Online Judge(AOJ)が提供している「プログラミング入門」(ITP1)の7_D問題をC++とPython で解いてみました。

ITP1 のトピック7では、再び構造化プログラムについて学びます。「繰り返し処理や配列を組み合わせることで、構造化プログラミングの理解を深めます。」とあります。この学習コースを通じて、Python に慣れていきたいと考えています。

問題(7_D: Matrix Multiplication)

問題はリンク先をご覧ください。

AOJ ITP1 7_D問題:Matrix Multiplication

行列の積を計算します。

解答案

ITP1 の問題6_D で行列とベクトルの積を求めました。今回は、行列と行列の積を求めます。$n \times m$ の行列 $A$ と $m \times l $ の行列 $B$ の積である、$n \times l$ の行列 $C$ について、数式で書くと以下となります。

$$\begin{pmatrix} c_{11} & \ldots & c_{1l} \\ c_{21} & \ldots & c_{2l} \\ \vdots & \cdots & \vdots \\ c_{n1} & \ldots & c_{nl} \end{pmatrix} = \begin{pmatrix} a_{11} & \ldots & a_{1m} \\ a_{21} & \ldots & a_{2m} \\ \vdots & \cdots & \vdots \\ a_{n1} & \ldots & a_{nm} \end{pmatrix} \begin{pmatrix} b_{11} & \ldots & b_{1l} \\ b_{21} & \ldots & b_{2m} \\ \vdots & \cdots & \vdots \\ b_{m1} & \ldots & b_{ml} \end{pmatrix}$$

行列 $C$ の各要素 $c_{ij}$ は次の式で得られます。

$$c_{ij} = \sum^m_{k = 1} a_{jk}b_{kj}$$

初めて見る方は、複雑な式だと感じるかもしれません。

C++ プログラム例(ITP1 7_D)

2次元配列で行列を表現して、前述の行列の積の定義に従って、計算するだけです。

問題文および上の解説では、添え字を1から記しましたが、以下のプログラムは、無駄な配列が出ないように添え字を0から使っています。これは、問題6_Dの場合と同じです。

$a_{jk}$、$b_{kj}$ は、それぞれ最大1万、積の最大は1億になります。それを最大100回加えるため、合計の最大値は100億になります。32ビット整数は、約20億までの数字しか格納できないため、行列積の要素は、long long int 型の整数 answer に格納します(25 行目)。(この記述は、2023年2月19日に追記しました。)

#include <iostream>

using namespace std;

int main()
{
	int n, m, l;
	cin >> n >> m >> l;

	int a[n][m], b[m][l];

	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			cin >> a[i][j];
		}
	}
	for (int j = 0; j < m; ++j) {
		for (int k = 0; k < l; ++k) {
			cin >> b[j][k];
		}
	}

	for (int i = 0; i < n; ++i) {
		for (int k = 0; k < l; ++k) {
			long long int answer = 0;
			for (int j = 0; j < m; ++j) {
				answer += a[i][j] * b[j][k];
			}
			cout << answer << " \n"[k == l - 1];
		}
	}

	return 0;
}

Python プログラム例(ITP1 7_D)

Python では、リストを使います。行列の演算については、NumPy という拡張モジュールを使うこともできますが、素の Python の範囲で実装しました。

変数 $l$ を使うとコーディングチェックツール pylint が警告を出力しました。1と見間違いやすいからだと思われます。このプログラムは、ループ変数を3個必要とするため、適当な変数名がなく、変数名 $l$ を許容することにしました。

n, m, l = map(int, input().split())
a = [[0 for i in range(m)] for j in range(n)]
b = [[0 for i in range(l)] for j in range(m)]
c = [[0 for i in range(l)] for j in range(n)]

for i in range(n):
    a[i] = list(map(int, input().split()))
for i in range(m):
    b[i] = list(map(int, input().split()))

for i in range(n):
    for j in range(l):
        for k in range(m):
            c[i][j] += a[i][k] * b[k][j]

for i in range(n):
    print(*c[i])

上記プログラムは、すべて AOJ で「AC(Accepted=正解)」と判定されます。

最後に

構造化プログラムの応用として、行列の積を計算しました。行列の演算は、昔は高校数学として履修していました。今は大学で線形代数という科目で学ぶ方が多いと思われます。

トピック7まで進み、プログラムできる範囲が広がりました。

引き続き、ITP1 の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA