Una forma directa es un procedimiento recursivo que hace lo siguiente en cada invocación. La entrada al procedimiento es una lista de pares que ya han sido elegidos y una lista de todos los pares.
- Calcule el número más pequeño que aún no está cubierto por la lista de entrada. Para la primera invocación, esto será 0, por supuesto, porque no se han elegido pares.
- Si todos los números están cubiertos, tiene una combinación correcta, imprímala y devuelva el paso anterior. De lo contrario, el número más pequeño que se descubre es el objetivo al que apuntaremos.
- Busque entre los pares buscando una forma de cubrir el número objetivo. Si no hay ninguno, simplemente regrese al nivel anterior de recursión.
- Si hay una manera de cubrir el número objetivo, elija la primera forma y llame de forma recursiva a todo el procedimiento nuevamente, con el par recién seleccionado y agregue a la lista de pares elegidos.
- Cuando eso regrese, busque la siguiente forma de cubrir el número objetivo con un par, sin superponer un par elegido previamente. Si encuentra uno, selecciónelo y vuelva a llamar recursivamente al siguiente procedimiento.
- Continúe los pasos 4 y 5 hasta que no haya más formas de cubrir el número objetivo. Ir a través de la lista completa de pares. Cuando no haya más opciones correctas, regrese al nivel anterior de la recursión.
La forma de visualizar este algoritmo es con un árbol cuyas rutas son secuencias de pares no superpuestos. El primer nivel del árbol contiene todos los pares que contienen 0. Para el ejemplo anterior, el árbol es
Raíz
El |
----------------
El | El | El |
(0,1) (0,2) (0,3)
El | El | El |
(2,3) (1,3) (1,2)
En este ejemplo, todas las rutas a través del árbol en realidad dan colecciones correctas, pero, por ejemplo, si omitimos el par (1,2), la ruta más a la derecha tendría solo un nodo y correspondería a la búsqueda en el paso 3 que falla.
Los algoritmos de búsqueda de este tipo pueden desarrollarse para muchos problemas similares de enumerar todos los objetos de un tipo particular.
Se sugirió que tal vez el OP significaba que todos los pares estaban en la entrada, no solo un conjunto de ellos como dice la pregunta. En ese caso, el algoritmo es mucho más fácil porque ya no es necesario verificar qué pares están permitidos. Ni siquiera es necesario generar el conjunto de todos los pares; El siguiente pseudocódigo hará lo que el OP solicitó. Aquí es el número de entrada, "lista" comienza como una lista vacía, y "cubierto" es una matriz de longitud n inicializada a 0. Podría hacerse algo más eficiente, pero ese no es mi objetivo inmediato.nortenorte
sub cover {
i = 0;
while ( (i < n) && (covered[i] == 1 )) {
i++;
}
if ( i == n ) { print list; return;}
covered[i] = 1;
for ( j = 0; j < n; j++ ) {
if ( covered[j] == 0 ) {
covered[j] = 1;
push list, [i,j];
cover();
pop list;
covered[j] = 0;
}
}
covered[i] = 0;
}