Uma maneira direta é um procedimento recursivo que faz o seguinte em cada chamada. A entrada para o procedimento é uma lista de pares que já foram escolhidos e uma lista de todos os pares.
- Calcule o menor número ainda não coberto pela lista de entrada. Para a primeira invocação, será 0, é claro, porque nenhum par foi escolhido.
- Se todos os números estiverem cobertos, você tem uma combinação correta, imprima-a e retorne a etapa anterior. Caso contrário, o menor número descoberto é a meta que almejamos.
- Pesquise os pares procurando uma maneira de cobrir o número de destino. Se não houver, retorne ao nível anterior de recursão.
- Se houver uma maneira de cobrir o número de destino, escolha a primeira e recursivamente chame todo o procedimento novamente, com o par escolhido apenas adicionado à lista de pares escolhidos.
- Quando isso retornar, procure a próxima maneira de cobrir o número de destino com um par, sem sobrepor um par escolhido anteriormente. Se você encontrar um, escolha-o e chame novamente recursivamente o próximo procedimento.
- Continue as etapas 4 e 5 até que não haja mais maneiras de cobrir o número de destino. Percorra a lista inteira de pares. Quando não houver mais opções corretas, retorne ao nível anterior da recursão.
A maneira de visualizar esse algoritmo é com uma árvore cujos caminhos são sequências de pares não sobrepostos. O primeiro nível da árvore contém todos os pares que contêm 0. No exemplo acima, a árvore é
Raiz
|
----------------
| | |
(0,1) (0,2) (0,3)
| | |
(2,3) (1,3) (1,2)
Neste exemplo, todos os caminhos na árvore realmente fornecem coleções corretas, mas, por exemplo, se deixássemos de fora o par (1,2), o caminho mais à direita teria apenas um nó e corresponderia à falha na etapa 3 da pesquisa.
Algoritmos de pesquisa desse tipo podem ser desenvolvidos para muitos problemas semelhantes de enumerar todos os objetos de um tipo específico.
Foi sugerido que talvez o OP significasse que todos os pares estão na entrada, não apenas um conjunto deles, como diz a pergunta. Nesse caso, o algoritmo é muito mais fácil, porque não é mais necessário verificar quais pares são permitidos. Nem é necessário gerar o conjunto de todos os pares; o pseudocódigo a seguir fará o que o OP pediu. Aqui é o número de entrada, "lista" começa como uma lista vazia e "coberto" é uma matriz de comprimento n inicializada como 0. Poderia ser um pouco mais eficiente, mas esse não é meu objetivo imediato.nn
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;
}