Medio · bucles 2D
Multiplicación de matrices
Cada celda de salida es un producto escalar: la fila i de A camina de la mano con la columna j de B, y la dimensión intermedia m es lo único que comparten. Con los tres papeles claros — A es n×m, B es m×k, C es n×k — el código se escribe solo.
En una frase<code>C[i][j] = suma sobre t de A[i][t] * B[t][j]</code> — tres bucles, C puesta a cero celda a celda, dimensiones n×m, m×k → n×k.
El problema
Entrada: La primera línea trae n, m, k (cada uno entre 1 y 10). Luego n líneas de m enteros: la matriz A. Después m líneas de k enteros: la matriz B. Valores entre −100 y 100.
Salida: n líneas de k enteros: el producto A×B, valores separados por un espacio.
Ejemplos:
| Entrada | Salida |
|---|---|
2 2 2 | 19 22 |
1 1 1 | 12 |
Comprueba a mano la primera celda: C[1][1] = 1·5 + 2·7 = 19. Fila encuentra columna, multiplica por parejas y suma — si sabes hacer una celda, los bucles solo las hacen todas.
Tu solución
Entrada personalizada para «Ejecutar mi entrada»
La corrección corre en tu navegador contra pruebas ocultas. Un bucle infinito se corta a los 3 segundos — aun así, asegúrate de que todo bucle tenga salida. Tu código se guarda solo mientras escribes.
¿Atascado? Pistas
Pista 1 — Pon a cero cada celda tú mismo
C es un array global, y en el motor de este sitio los arrays globales no se ponen a cero automáticamente (el C++ real sí; nuestro intérprete no). Es un buen hábito de todos modos: C[i][j] = 0; como primera línea dentro de los bucles i/j, y acumular con +=. Cuando hay memoria de por medio, explícito siempre gana a implícito.
Pista 2 — El índice del medio es la bisagra
El índice de suma t recorre m — las columnas de A y las filas de B. Un cambio de papeles frecuente escribe A[t][i] o B[j][t]; ambos compilan y ambos están mal. Di la forma en voz alta una vez: A es n por m, B es m por k — ese m compartido es lo que hace definida la multiplicación.
Pista 3 — Imprime con la disciplina del juez
Filas separadas por espacios, salto de línea al final de cada fila, sin espacio tras el último número: imprime el separador antes de cada valor salvo el primero, igual que en Ordenamiento burbuja. El formato de salida es parte del enunciado, no un detalle.
Solución (¡inténtalo primero!)
#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;
}
El triple bucle que acabas de escribir es, palabra por palabra, lo que las bibliotecas BLAS optimizan a gigaflops — las matemáticas nunca cambian, solo la disposición en memoria. Ya dominas el trío 2D completo: sumar (Sumar una matriz), reindexar (Transponer una matriz) y combinar (esta). Lo que queda en la tierra de las cuadrículas es preguntar por rectángulos — Sumas por rangos 2D.
Análisis profundo
Por qué funciona
Cada celda de salida es un producto escalar: la fila i de A contra la columna j de B, sumado sobre la dimensión compartida m. El triple bucle es la definición leída en voz alta — n×k celdas, cada una sumando m productos. No hay nada que demostrar; la dificultad es puramente mantener tres dimensiones en su carril.
El coste
O(n·m·k) — aquí 10×10×10 = 1.000 multiplicaciones-sumas. El mismo bucle a 1000×1000 son mil millones de operaciones, y por eso existen las bibliotecas (BLAS): la misma matemática, la memoria reordenada.
Dónde falla
- Intercambiar papeles en el producto interior:
A[t][i]oB[j][t]compilan bien y están mal. La bisagra esA[i][t] * B[t][j]— fila de A, columna de B. - Confiar en los globales a cero: en este motor los arrays globales no se ponen a cero, así que
C[i][j] = 0;dentro del bucle es obligatorio, no estilístico. - Disciplina de salida: separador antes de cada valor salvo el primero de cada fila, salto de línea al final — el juez compara caracteres, no intenciones.
Siguiente paso
Ya tienes el trío 2D completo: sumar (Sumar una matriz), reindexar (Transponer una matriz), combinar (esta). La siguiente habilidad con cuadrículas pregunta por rectángulos: Sumas por rangos 2D.
Dos cosas para recordar
- C[i][j] = Σ A[i][t]·B[t][j] — el m compartido es lo que lo hace definido.
- Pon a cero los acumuladores explícitamente; nunca confíes en que un array global empiece limpio.
🐞 Esta versión falla: ábrela y pruébala
El bucle interno corre hasta k en vez de m — solo los tests cuadrados lo perdonan
#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;
}