中 · 二重循环
矩阵乘法
每个输出格子都是一次点积:A 的第 i 行和 B 的第 j 列手牵手走,中间维度 m 是它们唯一共享的东西。把三个角色分清 —— A 是 n×m,B 是 m×k,C 是 n×k —— 代码自己就写出来了。
一句话答案<code>C[i][j] = 对 t 求和 A[i][t] * B[t][j]</code> —— 三重循环,C 逐格清零,维度 n×m、m×k → n×k。
题目
输入: 第一行是 n、m、k(每个 1 ≤ ≤ 10)。接下来 n 行、每行 m 个整数:矩阵 A。然后 m 行、每行 k 个整数:矩阵 B。取值 −100 到 100。
输出: n 行、每行 k 个整数:乘积 A×B,数字间单个空格。
样例:
| 输入 | 输出 |
|---|---|
2 2 2 | 19 22 |
1 1 1 | 12 |
手算第一个格子:C[1][1] = 1·5 + 2·7 = 19。行碰上列,逐对相乘、求和 —— 会算一个格子,循环就是把所有格子都算一遍。
你的解答
「运行我的输入」用的自定义输入
判题在浏览器本地运行。死循环会在 3 秒后被自动中断 —— 但还是确保每个循环都有出口。代码随打随存。
卡住了?提示
提示 1 — 每个格子自己清零
C 是全局数组,而本站引擎的全局数组不会自动清零(真实 C++ 会,我们的解释器不会)。无论如何这都是好习惯:在 i/j 循环内第一行写 C[i][j] = 0;,再用 += 累加。凡涉及内存,显式总比隐式可靠。
提示 2 — 中间那个下标是合页
求和下标 t 走的是 m —— A 的列数、B 的行数。常见的手滑写成 A[t][i] 或 B[j][t]:都能编译,全都是错的。把形状念一遍:A 是 n 行 m 列,B 是 m 行 k 列 —— 正是这个共享的 m 让乘法有意义。
提示 3 — 打印要有判题同款的纪律
行内空格隔开、行尾换行、每行最后一个数后面不带空格:在每个非首个值之前打印分隔符 —— 和 冒泡排序 里的做法一样。输出格式是题面的一部分,不是细节。
题解(先自己试试!)
#include <iostream>
using namespace std;
int A[12][12], B[12][12], C[12][12];
int main() {
int n, m, k;
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> A[i][j];
for (int i = 0; i < m; i++)
for (int j = 0; j < k; j++)
cin >> B[i][j];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
C[i][j] = 0;
for (int t = 0; t < m; t++) {
C[i][j] += A[i][t] * B[t][j];
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
cout << C[i][j];
if (j < k - 1) cout << " ";
}
cout << endl;
}
return 0;
}
你刚写的三重循环,一字不差就是 BLAS 库优化到每秒十亿次运算的东西 —— 数学从不改变,改变的只是内存布局。二维三件套你已集齐:求和(矩阵求和)、换下标(矩阵转置)、组合(本题)。网格这条线剩下的,就是向矩形提问 —— 二维区间求和。
深度解析
为什么这样做对
每个输出格子是一次点积:A 的第 i 行对着 B 的第 j 列,沿共享维度 m 求和。三重循环就是把定义念出声 —— n×k 个格子,每格 m 次乘加。没有东西需要证明;难点纯粹是让三个维度各就各位。
代价
O(n·m·k) —— 本题 10×10×10 = 一千次乘加。同样的循环放到 1000×1000 就是十亿次运算,这正是 BLAS 这类库存在的理由:数学不变,变的是内存布局。
常见错法
- 点积里角色互换:
A[t][i]或B[j][t]都能编译、都是错的。合页是A[i][t] * B[t][j]—— A 的行、B 的列。 - 信任全局自动清零:本引擎的全局数组不清零,循环内那句
C[i][j] = 0;是强制的,不是风格。 - 输出纪律:除每行第一个外,每个值之前打分隔符,行尾换行 —— 判题比对的是字符,不是心意。
记住这两句
- C[i][j] = Σ A[i][t]·B[t][j] —— 共享的 m 让乘法有意义。
- 累加格子显式清零;永远别指望全局数组天生干净。
🐞 这段是错的 —— 点开,亲手让它挂一次
内层循环跑到 k 而不是 m —— 只有方阵测试肯原谅它
#include <iostream>
using namespace std;
int A[12][12], B[12][12], C[12][12];
int main() {
int n, m, k;
cin >> n >> m >> k;
for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) cin >> A[i][j];
for (int i = 0; i < m; i++) for (int j = 0; j < k; j++) cin >> B[i][j];
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
C[i][j] = 0;
for (int t = 0; t < k; t++) { // bug: k instead of m
C[i][j] += A[i][t] * B[t][j];
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < k; j++) {
cout << C[i][j];
if (j < k - 1) cout << " ";
}
cout << endl;
}
return 0;
}