MCD, MCM y Algoritmo de Euclides
Domina el cálculo del Máximo Común Divisor y Mínimo Común Múltiplo usando el algoritmo de Euclides
Máximo Común Divisor (MCD/GCD)
El Máximo Común Divisor (MCD o GCD en inglés) de dos números es el número más grande que divide a ambos.
Ejemplos
- porque los divisores de 12 son 12 y los de 18 son 18. El mayor común es 6.
- (son coprimos)
Método ingenuo
Verificar todos los divisores posibles:
int gcdIngenuo(int a, int b) {
int resultado = 1;
for (int i = 1; i <= min(a, b); i++) {
if (a % i == 0 && b % i == 0) {
resultado = i;
}
}
return resultado;
}
Complejidad: - Muy lento para números grandes.
Algoritmo de Euclides
El Algoritmo de Euclides es uno de los algoritmos más antiguos conocidos (¡más de 2300 años!) y es extremadamente eficiente.
La idea clave
Se basa en esta propiedad fundamental:
¿Por qué funciona? Si divide tanto a como a , entonces también divide a para cualquier . En particular, divide a .
Ejemplo paso a paso
Calcular :
gcd(48, 18): 48 mod 18 = 12 → gcd(18, 12)
gcd(18, 12): 18 mod 12 = 6 → gcd(12, 6)
gcd(12, 6): 12 mod 6 = 0 → gcd(6, 0)
gcd(6, 0): resultado = 6
Implementación recursiva
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
Implementación iterativa
int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
Usando la STL (C++17+)
#include <numeric> // Para std::gcd
int main() {
int a = 48, b = 18;
cout << __gcd(a, b) << endl; // Funciona en todas las versiones
cout << gcd(a, b) << endl; // C++17+
return 0;
}
Complejidad: - ¡Muy rápido!
💡 ¿Por qué es tan eficiente?
En cada paso, al menos uno de los números se reduce a la mitad. Si , entonces . Esto significa que el algoritmo hace a lo más operaciones.
Mínimo Común Múltiplo (MCM/LCM)
El Mínimo Común Múltiplo (MCM o LCM en inglés) de dos números es el número más pequeño que es divisible por ambos.
Relación con el MCD
Existe una relación fundamental:
Implementación
long long lcm(long long a, long long b) {
return a / __gcd(a, b) * b; // División primero para evitar overflow
}
⚠️ Importante: Hacemos
a / gcd(a, b) * ben lugar dea * b / gcd(a, b)para evitar overflow cuando es muy grande.
Ejemplo
Verificación: 36 es divisible por 12 y por 18, y no hay número menor con esa propiedad.
Algoritmo de Euclides Extendido
El algoritmo extendido no solo calcula , sino que también encuentra enteros e tales que:
Esto se conoce como la Identidad de Bézout.
Implementación
int gcdExtendido(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int x1, y1;
int g = gcdExtendido(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return g;
}
Ejemplo
Para , el algoritmo encuentra e :
Aplicaciones
- Encontrar inversos modulares (lo veremos en aritmética modular)
- Resolver ecuaciones diofánticas lineales
- Criptografía (RSA)
Propiedades importantes
Propiedades del MCD
- (conmutativa)
- (asociativa)
- Si , decimos que y son coprimos
Propiedades del MCM
GCD/LCM de múltiples números
MCD de un arreglo
int gcdArreglo(vector<int>& arr) {
int resultado = arr[0];
for (int i = 1; i < arr.size(); i++) {
resultado = __gcd(resultado, arr[i]);
if (resultado == 1) break; // No puede ser menor
}
return resultado;
}
MCM de un arreglo
long long lcmArreglo(vector<int>& arr) {
long long resultado = arr[0];
for (int i = 1; i < arr.size(); i++) {
resultado = resultado / __gcd(resultado, (long long)arr[i]) * arr[i];
}
return resultado;
}
Problemas de práctica
Problema 1: GCD de consultas
Dado un arreglo, responde consultas del GCD de rangos.
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, q;
cin >> n >> q;
vector<int> arr(n);
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
// Tabla dispersa para consultas de GCD
int LOG = log2(n) + 1;
vector<vector<int>> tabla(LOG, vector<int>(n));
// Caso base
for (int i = 0; i < n; i++) {
tabla[0][i] = arr[i];
}
// Llenar tabla
for (int j = 1; j < LOG; j++) {
for (int i = 0; i + (1 << j) <= n; i++) {
tabla[j][i] = __gcd(tabla[j-1][i], tabla[j-1][i + (1 << (j-1))]);
}
}
// Responder consultas
while (q--) {
int l, r;
cin >> l >> r;
l--; r--; // 0-indexed
int k = log2(r - l + 1);
int resultado = __gcd(tabla[k][l], tabla[k][r - (1 << k) + 1]);
cout << resultado << "\n";
}
return 0;
}
Problema 2: Fracciones
Simplifica una fracción :
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
int g = __gcd(abs(a), abs(b));
a /= g;
b /= g;
// Asegurar que el signo esté en el numerador
if (b < 0) {
a = -a;
b = -b;
}
cout << a << "/" << b << endl;
return 0;
}
Problema 3: Ecuación Diofántica
Encuentra una solución entera a (si existe):
#include <bits/stdc++.h>
using namespace std;
int gcdExtendido(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int x1, y1;
int g = gcdExtendido(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return g;
}
int main() {
int a, b, c;
cin >> a >> b >> c;
int x, y;
int g = gcdExtendido(abs(a), abs(b), x, y);
if (c % g != 0) {
cout << "No hay solución" << endl;
} else {
x *= c / g;
y *= c / g;
if (a < 0) x = -x;
if (b < 0) y = -y;
cout << "x = " << x << ", y = " << y << endl;
cout << "Verificación: " << a << "*" << x << " + " << b << "*" << y << " = " << a*x + b*y << endl;
}
return 0;
}
Resumen
| Operación | Fórmula/Algoritmo | Complejidad |
|---|---|---|
| GCD | Algoritmo de Euclides | |
| LCM | ||
| GCD Extendido | Encuentra tal que |
Ejercicios recomendados
- Codeforces - GCD Problem
- SPOJ - CEQU - Ecuación Diofántica
- AtCoder - LCM Puzzle
