本サイトAIZU ONLINE JUDGE ITP1_7_D へはこちらから
問題:行列の積
\(n×m\) の行列 \(A\) と \(m×l\) の行列 \(B\) を入力し、それらの積である \(n×l\) の行列 \(C\) を出力するプログラムを作成してください。行列 \(C\) の各要素 \(c_{ij}\) は次の式で得られます:
$$c_{ij} = \sum_{k=1}^m a_{ik}b_{kj}$$
ここで、\(A\)、\(B\)、\(C\) の各要素をそれぞれ \(a_{ij}\)、\(b_{ij}\)、\(c_{ij}\) とします。
Input
1行目に \(n\)、\(m\)、\(l\) が空白区切りで与えられます。
続く行に \(n×m\) の行列 \(A\) と \(m×l\) の行列 \(B\) が与えられます。
Output
\(n×l\) の行列 \(C\) の要素 \(c_{ij}\) を出力してください。各行の隣り合う要素を1つの空白で区切ってください。
Constraints
- 1≤\(n,m,l\)≤100
- 0≤\(a_{ij},b_{ij}\)≤10000
Sample Input
3 2 3
1 2
0 3
4 5
1 2 1
0 3 2
Sample Output
1 8 5
0 9 6
4 23 14
解答例
n, m, l = map(int, input().split())
A = [list(map(int, input().split())) for _ in range(n)]
B = [list(map(int, input().split())) for _ in range(m)]
for i in range(n):
C = []
for j in range(l):
tmp = 0
for k in range(m):
tmp += A[i][k] * B[k][j]
C.append(tmp)
print(*C)
解説
以下のように解いていきます。
3つの整数の読み込み
ここではmap関数を使用します。第二引数のinput().split()で空白区切りの文字列を取得した値を、一つずつint関数に当てはめてint型に変換、n、m、l に設定していきます。
# input().split()で空白区切りの文字列を取得 → intに変換 → n, m, l に設定
n, m, l = map(int, input().split())
※サイト内「AIZU ONLINE JUDGE ITP1_1_Cをpythonで解いてみた」の、map関数とはに使用方法が書かれておりますのでぜひご覧ください。
行列Aの読み込み
まず、map関数を使用し、m個の数字の入力を行います。第二引数のinput().split()で空白区切りの文字列を取得した値を、一つずつint関数に当てはめてint型に変換、さらに、list関数で囲みます。
続いて、for文のイテラブルにrange(n)を設定し、m個の数字の入力処理であるlist(map(int, input().split()))をn回行います。
これでm個の数字のかたまりが、n個のリストが作成されます。
# input().split()で空白区切りの文字列を取得 → intに変換 → list関数で囲み、リストとしてm個の数値を受け取る
# さらに【for _ in range(n)】でm個の数値の受け取りをn回行う
A = [list(map(int, input().split())) for _ in range(n)]
※サイト内「AIZU ONLINE JUDGE ITP1_6_Bをpythonで解いてみた」の、リスト内包表記とはに使用方法が書かれておりますのでよかったらご覧ください。
Sample Inputを例にすると以下のようにリストに設定されます。
# 入力
3 2 3
1 2
0 3
4 5
# n(2)個のリストをm(3)回繰り返し、リストに設定
[[1, 2], [0, 3], [4, 5]]
行列Bの読み込み
まず、map関数を使用し、l個の数字の入力を行います。第二引数のinput().split()で空白区切りの文字列を取得した値を、一つずつint関数に当てはめてint型に変換、さらに、list関数で囲みます。
続いて、for文のイテラブルにrange(m)を設定し、l個の数字の入力処理であるlist(map(int, input().split()))をm回行います。
これでl個の数字のかたまりが、m個のリストが作成されます。
# input().split()で空白区切りの文字列を取得 → intに変換 → list関数で囲み、リストとしてl個の数値を受け取る
# さらに【for _ in range(m)】でl個の数値の受け取りをm回行う
B = [list(map(int, input().split())) for _ in range(m)]
行列の積Cの作成と表示
まずはじめに、行列どうしのかけ算には、以下の性質があります。
- 行列どうしのかけ算は、「左の行数」と「右の列数」が等しくないとかけ算できない
- 「n 行 m 列の行列」と「m 行 l 列の行列」の積が、「n 行 l 列の行列」となる
今回は、n×m の行列Aとm×lの行列Bの積から、n×lの行列Cを求め表示します。とはいっても、行列Cを求めてから表示するためには、作成用のfor文と表示用のfor文が必要ですが今回は作成と表示を同時に行います。
以下の①~⑤の順番で1行計算結果が出たところで表示します。
for i in range(n):
# ①出力用配列Cをリセット
C = []
for j in range(l):
# ②計算結果tmpをリセット
tmp = 0
for k in range(m):
# ③行列の積(1つの要素)を求め、tmpに保持
tmp += A[i][k] * B[k][j]
# ④計算結果tmpをCに追加
C.append(tmp)
# ⑤1行計算結果が出たところで表示
print(*C)
Sample Inputを例にすると以下のように計算されます。
# n(2)×m(3)の行列A
1 2
0 3
4 5
# m(3)×l(2)の行列B
1 2 1
0 3 2
# 行列A × 行列B イメージ①
行列A[[1, 2], [0, 3], [4, 5]] × 行列B[[1, 2, 1], [0, 3, 2]]
# 行列A × 行列B イメージ②
[1, 2] [1, 2, 1]
[0, 3] ×
[4, 5] [0, 3, 2]
# 行列A × 行列B イメージ③
1×1 + 2×0 , 1×2 + 2×3 , 1×1 + 2×2
0×1 + 3×0 , 0×2 + 3×3 , 0×1 + 3×2
4×1 + 5×0 , 4×2 + 5×3 , 4×1 + 5×2
# n×lの行列C
1 8 5
0 9 6
4 23 14
---------------------文字で表すと---------------------
# 行列X # 行列Y
a b A C E
c d B D F
e f
# 行列XYの積 行列Z
aA + bB , aC + bD , aE + bF
cA + dB , cC + dD , cE + dF
eA + fB , eC + fD , eE + fF
最後に、もう一度プログラムを確認してみましょう。
# input().split()で空白区切りの文字列を取得 → intに変換 → n, m, l に設定
n, m, l = map(int, input().split())
# input().split()で空白区切りの文字列を取得 → intに変換 → list関数で囲み、リストとしてm個の数値を受け取る
# さらに【for _ in range(n)】でm個の数値の受け取りをn回行う
A = [list(map(int, input().split())) for _ in range(n)]
# input().split()で空白区切りの文字列を取得 → intに変換 → list関数で囲み、リストとしてl個の数値を受け取る
# さらに【for _ in range(m)】でl個の数値の受け取りをm回行う
B = [list(map(int, input().split())) for _ in range(m)]
for i in range(n):
# ①出力用配列Cをリセット
C = []
for j in range(l):
# ②計算結果tmpをリセット
tmp = 0
for k in range(m):
# ③行列の積(1つの要素)を求め、tmpに保持
tmp += A[i][k] * B[k][j]
# ④計算結果tmpをCに追加
C.append(tmp)
# ⑤1行計算結果が出たところで表示
print(*C)
コメント