30. Principio del palomar

El principio del palomar afirma que, al distribuir más objetos que recipientes, al menos un recipiente debe contener varios objetos. Esta idea elemental permite demostrar la existencia inevitable de repeticiones, colisiones y agrupamientos.

30.1 Introducción

El principio del palomar, también llamado principio de Dirichlet, parece evidente: si hay más palomas que palomares, algún palomar debe alojar al menos dos palomas. Su potencia está en aplicarlo a objetos que no parecen palomas ni recipientes.

En programación, los objetos pueden ser datos, solicitudes, valores de un arreglo o mensajes; los recipientes pueden ser índices, clases de residuos, cubetas de una tabla hash o días del año. Identificar correctamente esta correspondencia es la parte creativa del razonamiento.

30.2 Formulación básica

Si se colocan n + 1 objetos en n recipientes, entonces al menos un recipiente contiene dos o más objetos.

Objetos > recipientes ⟹ existe una repetición.

13 personas y 12 meses de nacimiento:
al menos dos personas nacieron en el mismo mes.

El principio no dice cuáles son esas dos personas ni en qué mes nacieron. Garantiza solamente que una coincidencia existe.

30.3 Demostración por contradicción

Supongamos que n + 1 objetos se distribuyen en n recipientes y que ningún recipiente recibe más de un objeto. Entonces cada recipiente contiene como máximo un objeto.

n recipientes · 1 objeto por recipiente = como máximo n objetos.

Pero tenemos n + 1 objetos.
Esto es una contradicción.

La suposición era falsa, por lo que al menos un recipiente debe contener dos objetos. La prueba es corta, pero se reutiliza una y otra vez en problemas de conteo.

30.4 Objetos y recipientes

Antes de aplicar el principio debemos definir con precisión qué se está distribuyendo y dónde. Una mala elección puede llevar a una conclusión incorrecta.

Problema: 26 enteros cualesquiera.
Objetos: los 26 enteros.
Recipientes: los 24 residuos posibles no nulos y el residuo 0 módulo 25.

Conclusión: dos enteros tienen el mismo residuo módulo 25.

Los enteros pueden ser todos diferentes, pero al clasificarlos por su residuo solo hay 25 clases. Dos de ellos necesariamente caen en la misma clase.

30.5 Congruencias como recipientes

Los residuos módulo m forman exactamente m recipientes: 0, 1, ..., m - 1. Por ello, entre m + 1 enteros cualesquiera existen dos congruentes módulo m.

Con 8 enteros, módulo 7 hay 7 residuos posibles.

Por el principio del palomar, existen a y b distintos tales que:
a ≡ b (mod 7).
Equivalente: 7 divide a - b.

Esta observación une el principio con la aritmética modular. Es una fuente frecuente de demostraciones de divisibilidad y de resultados sobre ciclos.

30.6 Ejemplo: cumpleaños

Si ignoramos el 29 de febrero, hay 365 días posibles para un cumpleaños. En un grupo de 366 personas, al menos dos cumplen años el mismo día del año.

Objetos: 366 personas.
Recipientes: 365 fechas posibles.

366 > 365 ⟹ al menos una fecha tiene dos personas.

Este resultado es seguro. No debe confundirse con la pregunta probabilística de cuántas personas se necesitan para que una coincidencia sea probable: eso corresponde al problema del cumpleaños y requiere calcular probabilidades.

30.7 Ejemplo: pares con la misma diferencia

Consideremos seis enteros elegidos de 1 a 10. Cada uno puede asociarse a su distancia respecto de un valor fijo, por ejemplo 5, o a otra clasificación adecuada. El desafío consiste en escoger recipientes que representen la propiedad buscada.

Este tipo de ejercicio ilustra que el principio no sustituye el modelado: contar objetos y recipientes es simple después de decidir qué rasgo comparten los objetos que caen en un mismo recipiente.

30.8 Formulación generalizada

Si se colocan N objetos en k recipientes, entonces algún recipiente contiene al menos ⌈N/k⌉ objetos. El símbolo techo redondea hacia arriba.

N objetos, k recipientes ⟹ algún recipiente contiene al menos ⌈N/k⌉ objetos.

100 archivos en 9 servidores:
algún servidor aloja al menos ⌈100/9⌉ = 12 archivos.

No se afirma que todos los recipientes tengan esa cantidad. El resultado garantiza un mínimo para el recipiente más cargado.

30.9 Demostración de la forma general

Supongamos que ningún recipiente contiene ⌈N/k⌉ objetos. Entonces todos contienen a lo sumo ⌈N/k⌉ - 1 objetos.

Máximo total supuesto: k(⌈N/k⌉ - 1).

Como ⌈N/k⌉ - 1 < N/k,
k(⌈N/k⌉ - 1) < N.

No alcanzarían para alojar los N objetos: contradicción.

La fórmula general es la versión cuantitativa del principio básico. En vez de garantizar solo un par, garantiza cuántos objetos deben acumularse en algún recipiente.

30.10 Aplicación: distribución de tareas

Si se asignan 53 tareas a 8 trabajadores, incluso con una distribución tan equilibrada como sea posible, alguien recibirá al menos ⌈53/8⌉ = 7 tareas.

53 = 8·6 + 5.

Se pueden dar 6 tareas a cada trabajador y quedan 5 tareas.
Esas 5 obligan a que cinco trabajadores reciban una séptima tarea.

El principio proporciona una cota inevitable. No decide la política de reparto ni asegura equilibrio temporal, dificultad similar o disponibilidad de los trabajadores.

30.11 Funciones e inyectividad

Una función es inyectiva si elementos distintos del dominio siempre tienen imágenes distintas. Si el dominio finito tiene más elementos que el codominio, no puede existir una función inyectiva.

f: A → B.
Si |A| > |B|, f no es inyectiva.

Dos elementos distintos de A comparten la misma imagen en B.

Esta es la formulación abstracta del principio del palomar. Los objetos son los elementos del dominio; los recipientes son los valores posibles del codominio.

30.12 Colisiones en tablas hash

Una tabla hash con capacidad m transforma claves en uno de m índices. Si se insertan más de m claves distintas, por el principio del palomar al menos dos terminan en el mismo índice: ocurre una colisión.

Índice = hash(clave) mod m.

m cubetas y m + 1 claves distintas ⟹ al menos una colisión.

El módulo mantiene el índice en rango, pero no elimina colisiones.

Las implementaciones deben resolverlas mediante encadenamiento, direccionamiento abierto u otra estrategia. Una buena función hash busca repartir mejor las claves, no hacer imposible una colisión.

30.13 Detectar una colisión modular

function modulo(a, m) {
  return ((a % m) + m) % m;
}

function primeraColisionModulo(valores, m) {
  if (!Number.isInteger(m) || m <= 0) throw new Error("m debe ser positivo");

  const visto = new Map();
  for (const valor of valores) {
    const residuo = modulo(valor, m);
    if (visto.has(residuo)) {
      return { primero: visto.get(residuo), segundo: valor, residuo };
    }
    visto.set(residuo, valor);
  }
  return null;
}

console.log(primeraColisionModulo([11, 25, 8, 19], 7));
// { primero: 11, segundo: 25, residuo: 4 }

La función encuentra una colisión concreta si aparece. El principio del palomar garantiza que la función devolverá una colisión si recibe más de m valores, aunque los valores exactos no se conozcan de antemano.

30.14 Duplicados en un rango acotado

Un arreglo de n + 1 enteros no garantiza un duplicado si sus valores pueden ocupar n + 1 posibilidades distintas, por ejemplo de 0 a n. Para garantizar repetición, el rango debe contener como máximo n valores.

Caso garantizado:
n + 1 enteros, cada uno entre 0 y n - 1.
Hay n valores posibles ⟹ existe un duplicado.

Con valores de 0 a n hay n + 1 valores posibles y la repetición no está garantizada.

Es importante contar con precisión. Un error de uno en los límites puede cambiar una afirmación segura en una afirmación falsa.

30.15 Encontrar un duplicado con un conjunto

function primerDuplicado(valores) {
  const vistos = new Set();

  for (const valor of valores) {
    if (vistos.has(valor)) return valor;
    vistos.add(valor);
  }
  return null;
}

console.log(primerDuplicado([4, 9, 2, 7, 9, 1])); // 9
console.log(primerDuplicado([4, 9, 2, 7]));       // null

El principio prueba que un duplicado debe existir bajo ciertas condiciones; el algoritmo anterior lo localiza. Esta diferencia entre existencia matemática y construcción algorítmica es fundamental.

30.16 Garantía de existencia frente a algoritmo

El principio del palomar es no constructivo en su forma básica: asegura que hay una coincidencia, pero no identifica dónde está. Para encontrarla necesitamos inspeccionar los datos o una estructura auxiliar.

Demostración: con m + 1 valores hay una colisión módulo m.
Algoritmo: registrar cada residuo hasta observar uno repetido.

La demostración da certeza; el algoritmo produce el testigo concreto.

En informática teórica y diseño de algoritmos, esta distinción ayuda a separar una propiedad del problema de la estrategia usada para resolverlo.

30.17 Hashes criptográficos y colisiones

Un hash de longitud fija transforma un conjunto enorme de mensajes posibles en una cantidad finita de resultados. Por el principio del palomar, necesariamente existen mensajes distintos con el mismo hash.

Dominio: mensajes de longitud arbitraria, infinitos posibles.
Codominio: hashes de longitud fija, finitos posibles.

Las colisiones existen necesariamente.

La seguridad de un hash criptográfico no significa que no haya colisiones; significa que debería ser computacionalmente inviable encontrarlas de manera práctica. Para seguridad real se usan funciones y bibliotecas criptográficas reconocidas, no hashes inventados.

30.18 El principio no mide probabilidades

El principio responde a preguntas del tipo «¿es inevitable que ocurra?». No responde «¿qué tan probable es que ocurra antes de ese límite?».

Con 366 personas, una coincidencia de cumpleaños es segura.
Con menos personas, puede haber coincidencia o no.

Para estimar la probabilidad se necesita un modelo probabilístico adicional.

Mezclar garantía y probabilidad lleva a interpretaciones incorrectas en pruebas, capacidad de sistemas y seguridad de hashes.

30.19 Aplicación: límites de identificadores

Un identificador de k bits admite 2k valores distintos. Si se crean más de 2k objetos y cada uno recibe solo ese identificador, una repetición es inevitable.

Un identificador de 8 bits ofrece 28 = 256 valores.

Con 257 objetos, dos comparten identificador.
Un sistema debe detectar, resolver o impedir esa colisión.

La observación se aplica a códigos temporales, índices, nombres acortados y claves de una base de datos. Aumentar el espacio de identificadores reduce colisiones, pero un espacio finito siempre tiene un límite.

30.20 Estrategia para resolver problemas

  1. Identifica los objetos que se distribuyen.
  2. Define los recipientes según la propiedad que quieres obtener.
  3. Cuenta cuántos objetos y recipientes hay.
  4. Aplica la forma básica o generalizada del principio.
  5. Traduce «mismo recipiente» de nuevo al lenguaje del problema.

El último paso es crucial. Si los recipientes son residuos, caer en el mismo recipiente significa ser congruentes; si son cubetas, significa una colisión; si son meses, significa compartir mes de nacimiento.

30.21 Errores frecuentes

  • Contar incorrectamente los recipientes posibles, especialmente en rangos inclusivos.
  • Aplicar el principio cuando no hay más objetos que recipientes.
  • Concluir que se conoce cuál es la colisión, cuando solo se probó que existe.
  • Confundir una garantía de existencia con una probabilidad alta.
  • Suponer que una buena función hash puede evitar todas las colisiones.
  • No traducir correctamente qué significa que dos objetos estén en el mismo recipiente.

30.22 Qué debes recordar y conclusión

  • n + 1 objetos en n recipientes obligan a que algún recipiente tenga al menos dos objetos.
  • Con N objetos y k recipientes, alguno contiene al menos ⌈N/k⌉ objetos.
  • La parte importante es definir correctamente objetos y recipientes.
  • El principio prueba existencia, no localiza necesariamente el caso concreto.
  • Las clases de residuos, las tablas hash y los identificadores finitos son aplicaciones directas.
  • Una colisión inevitable no implica que sea fácil encontrarla.

El principio del palomar transforma un conteo sencillo en una demostración de existencia muy poderosa. En el próximo tema combinaremos conjuntos y contaremos elementos sin duplicarlos mediante el principio de inclusión y exclusión.