按定义直接三重循环:C[i][j] 是 A 第 i 行与 B 第 j 列的点积,枚举 i、j、t 累加,时间 O(nmk)。
OJ: roj
题目 ID: 1125
难度:入门
标签:入门矩阵数学python
创建: 2026-10-07 15:03
更新: 2026-10-07 15:03
形式化题目
给定整数矩阵
定义的
样例:
正解
思路
为什么没有别的做法。 定义已经把答案写死了:
- 枚举输出的行
( 种)与列 ( 种); - 对固定的
,枚举中间下标 ( 种),把 累加进一个临时变量 dot; - 把
dot写进,最后按行输出。
规模上界是
每个元素是"一行乘一列"。 下面的图画出
A 的第 i 行: (1 1)
B 的第 j 列: (1 1) -> 1*1 + 1*1 = 2 = C[i][j]样例里
| 元素 | 展开( |
结果 |
|---|---|---|
观察重点:三个格子只是 for (t = 1; t <= m; t++) 存在的唯一理由。
循环顺序可以换。 把
Python 里怎么写得短。 三层显式循环在 Python 里要写三层缩进,而"点积"正好可以交给标准库:先用 zip(*b) 把 math.sumprod(row, col) 一步算出点积。于是整个乘法只剩一行列表推导式,内层循环由 C 实现完成,代码短且不慢。
类型与溢出。 int 其实也放得下,但 C++ 代码统一用 long long 存放矩阵元素与点积,省掉"会不会刚好溢出"的推理;Python 整数本身没有溢出问题。
代码
Python 版:
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-07 15:03
# update_at: 2026-10-07 15:03
import sys
from collections.abc import Iterator
from math import sumprod
type Matrix = list[list[int]] # 矩阵按行存:matrix[i] 是第 i 行,元素是整数
type Tokens = Iterator[bytes] # 一次读入后按空白切分的整数流,顺序消费
def read_matrix(rows: int, cols: int, data: Tokens) -> Matrix:
"""从整数流里顺序取数,读入 rows 行 cols 列的矩阵。"""
return [[int(next(data)) for _ in range(cols)] for _ in range(rows)]
def multiply(a: Matrix, b: Matrix) -> Matrix:
"""按定义做矩阵乘法:C[i][j] = Σ_t A[i][t] * B[t][j]。"""
columns = list(zip(*b)) # zip(*b) 把 B 的第 j 列收成一个元组
return [[sumprod(row, col) for col in columns] for row in a] # sumprod 就是点积
def solve() -> None:
data = iter(sys.stdin.buffer.read().split())
n, m, k = int(next(data)), int(next(data)), int(next(data))
a = read_matrix(n, m, data)
b = read_matrix(m, k, data)
for row in multiply(a, b):
print(' '.join(map(str, row)))
if __name__ == "__main__":
solve()C++ 版(同一算法):
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-07 15:03
* update_at: 2026-10-07 15:03
*/
#include <cstdio>
typedef long long ll;
const int MAXN = 105;
ll a[MAXN][MAXN]; // A 矩阵:n 行 m 列,a[i][j] 是第 i 行第 j 列的元素
ll b[MAXN][MAXN]; // B 矩阵:m 行 k 列,b[t][j] 是第 t 行第 j 列的元素
ll c[MAXN][MAXN]; // C 矩阵:n 行 k 列,c[i][j] 是 A 第 i 行与 B 第 j 列的点积
int main() {
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%lld", &a[i][j]);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= k; j++)
scanf("%lld", &b[i][j]);
// 三重循环按定义算 C:外层枚举行 i 与列 j,内层枚举中间的 t 累加乘积
for (int i = 1; i <= n; i++)
for (int j = 1; j <= k; j++) {
ll dot = 0; // A 第 i 行与 B 第 j 列的点积,即 C[i][j]
for (int t = 1; t <= m; t++)
dot += a[i][t] * b[t][j];
c[i][j] = dot;
}
// 输出 C:每行 k 个整数,整数之间用一个空格分开
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) {
if (j > 1) printf(" ");
printf("%lld", c[i][j]);
}
printf("\n");
}
return 0;
}复杂度
- 时间复杂度:
。 有 个元素,每个元素花 做点积;输入规模本身就是 个数,读入不超过 (因为 )。上界 次乘加。 - 空间复杂度:
,即存下 、 、 三个矩阵。Python 版额外用 zip(*b)存了一份的列视图,同阶;总内存远低于 MB。
总结
- 矩阵乘法没有算法空间:按定义枚举
三重下标, 就是 第 行与 第 列的点积。 - 三层循环的顺序可以任意调换,整数加法满足交换律与结合律;
- - 最贴近公式, - - 对缓存更友好,本题规模下无差别。 - 复杂度
时间、 空间; 时最多 次乘加, ms 时限下余量充足。 - 边界:
、 、 都可能取 (真实数据里有 和 的极端形状),此时点积只有一项,代码不需要任何特判;元素含负数,答案也可能是负数,同样不需要特判。