Torres de Hanoi
description
Transcript of Torres de Hanoi
Estrutura de Dados
Torres de Hanoi
“No século XIX, um jogo chamado Torres de Hanoi apareceu na Europa, junto com um material promocional explicando que o jogo representava uma tarefa conduzida no Templo de Brahma (montanhas de Hanoi – sacerdotes brâmanes).
Dizia, ainda, que na criação do mundo, aos sacerdotes foi dada uma plataforma de metal na qual existiam três hastes de diamante.
Estrutura de Dados
Torres de Hanoi
Na primeira haste existiam 64 discos de ouro, cada um ligeiramente menor em relação ao que estava por cima. (A versão mais exótica vendida na época na Europa tinha 8 (oito) discos e 3 (três) hastes de madeira).
Estrutura de Dados
Torres de Hanoi
Os sacerdotes foram incumbidos com a tarefa de mover todos os discos de ouro do primeiro disco para o terceiro, porém, com as seguintes condições:
a. Mover apenas um disco por vez;
b. E nenhum disco poderia ficar sobre um disco menor.
Estrutura de Dados
Torres de Hanoi
Entretanto, poderiam utilizar qualquer haste de diamante como descanso para os discos.
Aos sacerdotes foi dito que quando eles terminassem de movimentar os 64 discos de ouro, significaria o fim do mundo!!!”
Estrutura de Dados
Torres de Hanoi
Estrutura de Dados
Desenvolvendo uma solução para Torres de Hanoi
Concentrar nossa atenção não no primeiro passo Mas sim, no passo mais difícil: mover o último
disco Como acessar o disco número 64? Lembre-se que somente um disco pode ser
movido por vez E o último (o maior) não pode nunca estar sobre
os demais Quando movemos o disco 1, não pode existir
nenhum outro disco nas torres 1 e 3
Estrutura de Dados
Resumindo os passos do algoritmo de Torres de Hanoi
Move (63, 1, 2, 3) Move 63 discos da torre 1 para 2 (torre 3 temporária)
Escreva: “Mova o disco número 64 da torre 1 para torre 3”
Move (63, 2, 3, 1) Move 63 discos da torre 2 para torre 3 (torre 1
temporária)
Estrutura de Dados
Refinamento
Para escrever o algoritmo na sua forma final, nós devemos saber em cada passo, qual torre será utilizada como armazenamento temporário, e assim, nós construímos a função “move” com as seguintes especificações:
void move(int qtd, int inicio, int fim, int aux) Pré-condição: Existe no mínimo qtd discos na torre inicio. O disco
de topo (se existir) nas torres aux e fim, é maior do que qualquer outros qtd discos presentes na torre inicio.
Pós-Condições: Os qtd discos que estavam na torre inicio foram movidos para a torre fim. A torre temp (usada como armazenamento temporário) retornou para sua posição inicial.
Estrutura de Dados
Refinamento
Nossa tarefa deve terminar num número finito de passos.
Uma regra óbvia é que, quando não existir mais discos para ser movido, não há mais nada para fazer...
Estrutura de Dados
Analisando um programa que considera as regras anteriores#define discos = 64; //faça essa constante ser menor para testar o programa
/*Pré: NenhumPós: A simulação das torres de Hanoi terminou*/void move(int qtd, int inicio, int fim, int aux);
main(){ move (discos, 1, 3, 2);}
void move(int qtd, int inicio, int fim, int aux){
if(qtd > 0){
move(qtd – 1, inicio, aux, fim);printf(“Mova disco %i de %i para %i”, qtd, inicio, fim);move(qtd - 1, aux, fim, inicio);
}}
Estrutura de Dados
Acompanhamento / Análise
Acompanhamento e análise do programa recursivo de Torres de Hanói com árvore de recursão.
Demonstração: move(3, 1, 3, 2);
Estrutura de Dados
Analisando a árvore de recursão
Uma instrução é exibida para cada vértice (ou nó)
Exceto para as folhas que são chamadas com count == 0
O número de vértices tipo não-folhas é: 1 + 2 + 4 +...+ 263 = 20 + 21 + 22+ . . . + 263 = 264 –1
Estrutura de Dados
Podemos concluir o seguinte
Número de movimentos para movimentar todos 64 discos é de: 264 -1
Este valor pode ser estimado por: 103 = 1000 1024 = 210
Número aproximado de movimentos é: 264 = 24 x 260 24 x 1018 = 1,6x1019
Existem aproximadamente 3,2x107 segundos num ano Suponha instruções num ritmo de um movimento por
segundo A tarefa total levará quase 5x1011 anos Estimativa de vida do universo: mínimo 20 bilhões
(2x1010) anos Duração do mundo: 25 vezes mais do que já tem!!!
Estrutura de Dados
Consideração de tempo (execução) e espaço (memória) do algoritmo recursivo de Torres de Hanoi
Não existiria um computador que rodaria o programa de Torres de Hanoi
Ele falharia por falta de tempo Mas certamente não por falta de espaço O espaço necessário é somente para fazer o
controle das 64 chamadas recursivas Mas o tempo necessário requerido, é aquele
para fazer 264 cálculos
Estrutura de Dados
Desenvolvendo algoritmos recursivos
Ache o passo chave Como este problema pode ser dividido? Como posso desenvolver o passo chave da solução?
Ache uma regra de parada Uma regra de parada indica que o problema ou uma parte
razoável do mesmo foi feito Ela é geralmente pequena e dá a solução trivial, sem a
necessidade da recursão
Monte seu algoritmo Combine a regra de parada e o “passo chave” usando uma
instrução if
Estrutura de Dados
Desenvolvendo algoritmos recursivos
Verifique o término Certificar que a recursão sempre terminará Comece com uma situação geral Verifique se num número finito de passos, a regra de
parada será satisfeita e a recursão termina Desenhe uma árvore de recursão
É a ferramenta chave para analisar algoritmos recursivos
Estrutura de Dados
Tipos de recursividadeRecursão de Cauda
Essa situação na qual a chamada recursiva é o último comando da função, é denominada recursão de cauda
Isso forma um “looping” que será repetido até que uma condição de parada seja satisfeita
A recursão de cauda pode sofrer transformações até ser obtida uma estrutura de interação, quando observaremos ganhos em tempo e espaço
Estrutura de Dados
ExemploFatorial/*Fatorial : versão recursivaPós : n é um inteiro não negativoPré : retorna o valor do fatorial de n*/int fatorial(int n){
if (n == 0)return 1;
elsereturn n*fatorial(n-1);
}
/*fatorial : versão interativaPós : n é um inteiro não negativoPré : retorna o valor do fatorial de n*/int fatorial(int n){
int count, product = 1;for(count = 1; count < = n; count ++)
product*= count;return product;
}
Estrutura de Dados
Considerando os exemplos anteriores Qual dos programas usa menos espaço de memória? Acompanhe a execução recursiva para n = 5
fatorial(5) = 5*fatorial(4)= 5*(4*fatorial(3))= 5*(4*(3*fatoriall(2)))= 5*(4*(3*(2*fatorial(1))))= 5*(4*(3*(2*(1*(fatorial(0))))))= 5*(4*(3*(2*(1*))))= 5*(4*(3*(2*1)))= 5*(4*(3*2))= 5*(4*6)= 5*24= 120
Estrutura de Dados
Diretrizes e conclusões gerais
A árvore de recursão é uma boa possibilidade para ajudar a decisão entre utilizar um algoritmo recursivo e não recursivo
Se ela tiver uma forma simples, a versão interativa pode ser melhor
Se ela envolver tarefas de duplicação, outras estruturas que não sejam pilhas poderão ser mais apropriadas, então a necessidade de recursão pode desaparecer
Se a árvore de recursão parece ser consistente, com poucas tarefas de duplicação, então a recursão pode ser o método mais natural
Estrutura de Dados
Ainda mais...
A recursão é considerada uma abordagem top-down para resolver um problema
A interação está mais para um abordagem bottom-up
É sempre verdadeiro que a recursão pode ser substituída pela interação e pilhas
É verdade também, por outro lado, que qualquer programa interativo que manipula uma pilha pode ser substituído por um programa recursivo sem nenhuma pilha
Estrutura de Dados
Mensagem sobre a utilização da recursão
“Um programador cuidadoso deve não somente perguntar, se a recursão deve ser removida, mas também perguntar, quando um programa usa pilhas, se a introdução da recursão poderia produzir um programa mais natural e de melhor entendimento, agregando melhorias na abordagem e nos resultados do problema”