Relações de recorrência

583 visualizações

Publicada em

Material de apoio das aulas de tutoria de Algoritmos e Estrutura de dados da Universidade Federal de Ouro Preto, Campus João Monlevade. O conteúdo abordado é sobre relações de recorrência em relação com a análise e complexidade de algoritmos.

Publicada em: Educação
0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
583
No SlideShare
0
A partir de incorporações
0
Número de incorporações
2
Ações
Compartilhamentos
0
Downloads
20
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Relações de recorrência

  1. 1. Tutoria AEDSI Pablo Silva
  2. 2. Mais de recursividade Vamos ver mais alguns exemplos de problemas que podemos resolver com recursividade
  3. 3. Seja o problema em que temos um número natural n >= 0 e queremos descobrir a soma de todos os números de n até 0. Como resolver este problema recursivamente?
  4. 4. Entender o problema matemático Precisamos sempre encontrar o caso base e o passo recursivo. Mas para isso, temos que entender o problema matemático.
  5. 5. Entender o problema matemático Vejamos possíveis iterações: 0 = 0 1 = 1 + 0 = 1 2 = 2 + 1 + 0 = 3 3 = 3 + 2 + 1 + 0 = 6 ... n = n + n-1 + n-2 + ... + 0 O caso base como podemos perceber é zero, pois é sempre onde o problema termina!
  6. 6. Entender o problema matemático Vejamos possíveis iterações: 0 = 0 1 = 1 + 0 = 1 2 = 2 + 1 + 0 = 3 3 = 3 + 2 + 1 + 0 = 6 ... n = n + n-1 + n-2 + ... + 0 O que podemos perceber analisando as iterações, é que começamos a somar em n e vamos diminuindo em 1 para cada número natural anterior a n até zero. n-1
  7. 7. Entender o problema matemático Se assumirmos que diminuímos o problema em um fator de 1, então teríamos a seguinte situação: 0 = 0 1 = + 0 = 1 2 = + 1 + 0 = 3 3 = + 2 + 1 + 0 = 6 ... n = + n + n-1 + ... + 0 Ao diminuirmos, percebemos que novamente, nessa iteração, teríamos após o n, um fator n-1 e então podemos definir nosso passo recursivo como: n + soma(n-1) Pois para resolver o problema, sempre somamos n com o seu antecessor direto (n- 1). n-1
  8. 8. Soma de n termos Nossa função então ficaria da seguinte forma: int soma(int n){ if(n == 0) return 0; return n + soma(n-1); }
  9. 9. Mais um exemplo Seja o problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 Percebemos que o problema termina sempre que k = 0. Portanto, desta vez, a diminuição do nosso problema, ocorrerá no expoente e não no número que estamos somando.
  10. 10. Um fato importante a se considerar sobre recursão - Nós podemos ter mais de um caso base! - Sempre precisamos encontrar uma maneira de diminuir o problema. O fator que vamos diminuir e qual é o nosso parâmetro de diminuição não será o mesmo para todos os problemas. Podemos, inclusive, ter que diminuir o problema utilizando mais que um parâmetro para isso. - É importante notar que o fator de diminuição nem sempre será em 1, pode por exemplo ser 2 ou até mesmo dividir o problema pela metade a cada passo recursivo!
  11. 11. Mais um exemplo Seja o problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 O caso base é fácil de perceber, pois quando k = 0, o problema terminou para todas as iterações. Logo k = 0 é o nosso caso base.
  12. 12. Mais um exemplo Seja o problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 Para o passo recursivo, percebemos que sempre podemos multiplicar n por uma potenciação de 𝑛 𝑘−1. O k-1 é em relação ao expoente inicial. Logo o passo recursivo: 𝑛 * 𝑛 𝑘−1
  13. 13. Potenciação recursiva Nossa função então ficaria da seguinte forma: int pot(int n, int k){ if(k == 0) return 1; return n * pot(n,k-1); }
  14. 14. Análise da recursividade Qual é a complexidade do algoritmo recursivo que calcula o fatorial de n? Como conseguimos calcular esse valor?
  15. 15. Análise da recursividade Analisar a complexidade de algoritmos recursivos não é tão simples assim e muitas vezes temos que utilizar recursos matemáticos mais aguçados para conseguir chegar à um valor.
  16. 16. Análise da recursividade Analisar a complexidade de algoritmos recursivos não é tão simples assim e muitas vezes temos que utilizar recursos matemáticos mais aguçados para conseguir chegar à um valor. Isto envolve saber a descrição matemática que nos dá o comportamento do algoritmo, que será definida como sua relação de recorrência! (recorrência, pois o algoritmo sempre “recorre” a si mesmo várias vezes para resolver um problema qualquer. Recorrência é o mesmo que repetição!)
  17. 17. Relações de recorrência Uma relação de recorrência é sempre formada por: o caso base e por um elemento que se parece muito com o passo recursivo, mas tem a ver com número de operações completadas. Vamos tentar entender um pouco deste elemento, utilizando o fatorial recursivo de n.
  18. 18. Relações de recorrência Seja uma relação de recorrência representada pelo símbolo 𝑇, podemos definir então a função de 𝑇(n), que será a função que descreverá nossa relação de recorrência, de modo que: 𝑇 𝑛 = 𝐶 , 𝑞𝑢𝑎𝑛𝑑𝑜 𝑛 𝑎𝑡𝑖𝑛𝑔𝑒 𝑜 𝑐𝑎𝑠𝑜 𝑏𝑎𝑠𝑒 𝑇 𝑛 𝑝𝑜𝑟 𝑎𝑙𝑔𝑢𝑚 𝑓𝑎𝑡𝑜𝑟 𝑑𝑒 𝑘 + 𝑑 𝑑 ≥< 0 Onde o valor mínimo de n depende do nosso problema matemático!
  19. 19. Relações de recorrência Vamos utilizar como exemplo o fatorial de n. Sabemos que o caso base é quando n = 1 e neste caso, o valor retornado é 1. Logo C = 1 quando n = 1, então: 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1
  20. 20. Relações de recorrência Agora vamos analisar a função fatorial, para encontrar nossa relação de recorrência: int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } Para encontrar a recorrência do algoritmo temos que nos atentar para o número de operações que temos a cada passo. Olhando para o passo recursivo, pode-se perceber que sempre vamos ter 1 multiplicação mais uma chamada da função fatorial com o nosso problema diminuído em 1. Portanto nossa recorrência pode ser definida por: 1 + 𝑇 𝑛 − 1 Onde T refere-se neste caso a função fatorial! Uma multiplicação e uma chamada de função com o problema diminuído em 1!
  21. 21. Relações de recorrência Logo, k = 1, o fator de diminuição é uma subtração por k e d = 1, que é o valor de operações completadas por cada chamada da função. 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 ,
  22. 22. Relações de recorrência Para finalizar o nosso T(n), precisamos definir o valor mínimo que n atinge em que a recorrência ainda existe. Neste caso, é todo valor que n assume que é maior que o caso base. Logo 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1 Quando n atingir 1, não teremos mais recorrências!
  23. 23. Como resolver uma relação de recorrência? Temos duas maneiras de resolver uma relação de recorrência: - Por expansão dos fatores - Por indução matemática
  24. 24. Resolvendo recorrências por expansão de fatores. Receita de bolo! 1º) Copie a fórmula original 𝑇 𝑛 = 𝑇 𝑛 − 1 + 1 2º) Descubra por quanto que a recorrência é diminuída a cada passo (fator de diminuição k) T(n) está escrito em função de T(n-1) então a cada passo o parâmetro n é subtraído de 1 (k = 1)
  25. 25. Resolvendo recorrências por expansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Como já sabemos que o fator de diminuição é subtraído de 1, então devemos achar os valores de T(n-1), T(n-2), T(n-3) e assim por diante, substituindo n pelos respectivos valores na equação inicial.
  26. 26. Resolvendo recorrências por expansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Se ainda está confuso o que devemos fazer, pense nesse problema matemático, seja: 𝑓 𝑥 = 2𝑥 Se queremos saber o valor de f(2) e f(3) logo x = 2, x = 3, então fazemos: 𝑓 2 = 2 ∗ 2 = 4 𝑓 3 = 2 ∗ 3 = 6
  27. 27. Resolvendo recorrências por expansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Portanto se queremos saber os valores de T(n-1), T(n-2)... Então n = n-1, n = n-2,... E fazemos como anteriormente substituindo os valores de n. Logo: 𝑇 (𝑛 − 1) = 𝑇 𝑛 − 1 − 1 + 1 = T n − 2 + 1 (3.1) 𝑇 (𝑛 − 2) = 𝑇 𝑛 − 2 − 1 + 1 = T n − 3 + 1(3.2) 𝑇 (𝑛 − 3) = 𝑇 𝑛 − 3 − 1 + 1 = T n − 4 + 1(3.3)
  28. 28. Resolvendo recorrências por expansão de fatores. Receita de bolo! 4º) Substitua os valores encontrados em 3, na equação original (chamamos isto de expansão da recorrência) T(n) = T(n-1) + 1 Utilizando 3.1, onde encontramos o valor de T(n-1): 𝑇 𝑛 = 𝑇 𝑛 − 2 + 1 + 1 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) Utilizando 3.2, onde encontramos o valor de T(n-2), substituímos em 4.1 𝑇 𝑛 = 𝑇 𝑛 − 3 + 1 + 2 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 (4.2) k k
  29. 29. Resolvendo recorrências por expansão de fatores. Receita de bolo! 4º) Continuamos a substituir, até conseguirmos enxergar um padrão nas expansões: Utilizando 3.2, onde encontramos o valor de T(n-3), substituímos em 4.2: 𝑇 𝑛 = 𝑇 𝑛 − 4 + 1 + 3 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 (4.3) Podemos notar que o valor de k incrementa a cada expansão, que é o comportamento experado, já que estamos sempre diminuindo a recorrência pelo fator de 1 (valor inicial de k). A ideia é perceber o comportamento da recorrência ao se aumentar o valor de k (diminuir a recorrência)! k
  30. 30. Resolvendo recorrências por expansão de fatores. Receita de bolo! 4º) Analisando todas as iterações: 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3 k A cada expansão da recorrência, k assume um novo valor. Percebemos também que o valor constante que é somado a recorrência e indica a quantidade de multiplicações que teremos que realizar para encontrar a solução do problema (fatorial de n) é o mesmo valor de k em todas as iterações.
  31. 31. Resolvendo recorrências por expansão de fatores. Receita de bolo! 4º) Analisando todas as iterações: 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3 k Logo, depois de k expansões teremos: 𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘
  32. 32. Resolvendo recorrências por expansão de fatores. Receita de bolo! 5º) Encontrar quando a expansão para. Precisamos pensar no caso base, que é o mesmo que pensar em quando T(n-k) nos retornará um valor. Olhando para o caso base, sabemos que teremos um valor de retorno e não uma nova recorrência quando n = 1. Para o nosso caso, n = (n-k) que é o valor de argumento da recorrência [T(n-k)] 𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘 (5.1) Logo precisamos saber quando n-k = 1, pois então teremos T(1) e já sabemos que isso é igual a 1. 𝑛 − 𝑘 = 1 ⇒ 𝑘 = 𝑛 − 1
  33. 33. Resolvendo recorrências por expansão de fatores. Receita de bolo! 5º) Substituindo o valor de k encontrado (n-1) em 5.1 temos 𝑇 𝑛 = 𝑇 𝑛 − (𝑛 − 1) + 𝑛 − 1 = 𝑇 1 + 𝑛 − 1 Como sabemos que T(1) = 1, então 𝑇 𝑛 = 1 + 𝑛 − 1 𝑇 𝑛 = 𝑛
  34. 34. Resolvendo recorrências por expansão de fatores. Receita de bolo! 6º) Definir o limite assintótico de T(n) Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de n recursivo é O(n), maior grau no polinômio encontrado. Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de recorrência é suficiente para conhecer a complexidade do algoritmo, porém se quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar indução matemática, que é um método da matemática discreta que nos ensina como provar problemas matemáticos, entre eles relações de recorrência.
  35. 35. Resolvendo recorrências por expansão de fatores. Receita de bolo! 6º) Definir o limite assintótico de T(n) Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de n recursivo é O(n), maior grau no polinômio encontrado. Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de recorrência é suficiente para conhecer a complexidade do algoritmo, porém se quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar indução matemática, que é um método da matemática discreta que nos ensina como provar problemas matemáticos, entre eles relações de recorrência.
  36. 36. Indução matemática Em uma linguagem bem simplificada. Você pode usar a indução matemática para provar uma expressão matemática quando: 1 – Sabe que ela é verdadeira para algum valor. 2 – Quer provar que ela é válida então para esse valor em relação a um fator de um (pode ser aumentar ou diminuir). Ou seja, quer provar que o próximo valor e os próximos valores depois deste também são verdadeiros.
  37. 37. Indução matemática Características: 1 – O passo 1 do slide anterior é chamado de passo base. 2 – O passo 2 é o passo indutivo.
  38. 38. Indução matemática Exemplo. Seja um teorema que tenha como parâmetro um número natural n. Provando que T é válido para todos os valores de n, provamos que: 1 – T é válido para n = 1 (eu tenho que saber que isto é verdade!); 2 – Para todo n > 1, se T é válido para n – 1, então T é válido para n (Se conseguirmos provar que n – 1 é válido (e isto implica em provar que n – 2, n – 3 e assim por diante também é válido), então podemos provar que n é verdadeiro. Esse é o passo indutivo.
  39. 39. O que é uma prova? Em matemática, uma prova é uma argumentação precisa que procura convencer o leitor de que uma certa preposição, previamente enunciada está correta. Num sentindo mais informa, uma prova é um texto que ajuda o leitor a entender por que uma dada afirmação é verdadeira!
  40. 40. Provando uma relação de recorrência por indução matemática Primeiro temos que provar que o passo base é verdadeiro. Para nossa equação de recorrência do problema do fatorial: 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1 Logo primeiro queremos provar que T(1) = 1. Sabemos que T(1) é verdadeiro, pois quando n = 1, o algoritmo não realiza nenhuma multiplicação. Logo, o nosso caso base é verdadeiro!
  41. 41. Provando uma relação de recorrência por indução matemática Agora supomos que T(k) = k (pois não sabemos quanto é realmente este valor antes de calcular todas as multiplicações. A variável n foi substituída por k, pois estamos generalizando para quaisquer valores n > 1, pois quando n = 1 já provamos ser verdadeiro). Para provar que T(k) = k é verdadeiro, precisamos provar que T(k + 1) = k + 1 também é verdadeiro. Se conseguirmos provar que T(k + 1) é verdadeiro, então T(k) também será verdadeiro, pois derivamos T(k+1) de T(k) e assim nosso passo indutivo seria verdadeiro e nossa relação de recorrência também.
  42. 42. Provando uma relação de recorrência por indução matemática A ideia principal aqui é a seguinte. Vamos encontrar definir nossa hipótese de indução. A hipótese de indução é sempre nosso passo recursivo: 𝑇 𝑛 = 𝑇 𝑛 − 1 + 1 Vamos a partir da nossa hipótese de indução, determinar o valor de T(k + 1).
  43. 43. Provando uma relação de recorrência por indução matemática 𝑇 𝑘 + 1 = 𝑇 (𝑘 + 1) − 1 + 1 = 𝑇 𝑘 + 1 Sempre, que queremos provar T(k+1), precisamos tentar deixá-lo em função de T(k), que é o valor que supomos no começo do exercício que queríamos provar. Supomos que T(k) = k, então vamos substituí-lo na expressão encontrada acima.
  44. 44. Provando uma relação de recorrência por indução matemática Como supomos que T(k) = k no começo do exercícios, podemos então substituí-lo na expressão encontrada no slide anterior: 𝑇 𝑘 + 1 = 𝑇 𝑘 + 1 T(k + 1) = 𝑘 + 1 Note que é exatamente o que queríamos provar, pois lembre-se que no começo do exercício, supomos T(k) = k e queríamos provar que T(k+1) = k +1.
  45. 45. Provando uma relação de recorrência por indução matemática Escrever uma prova de indução matemática sempre envolve: - Provar o caso base - Supor T(k) = k e tentar provar que T(k+1) = k+1 - Encontrar uma hipótese de indução, que é o nosso passo recursivo - Utilizar a hipótese de indução para encontrar T(k+1) em função de T(k) - Manipular T(k+1) para que ele seja k+1

×