IME ALGORITMOS. Paulo Eustáquio Duarte Pinto

Tamanho: px
Começar a partir da página:

Download "IME ALGORITMOS. Paulo Eustáquio Duarte Pinto"

Transcrição

1 IME ALGORITMOS Paulo Eustáquio Duarte Pinto Universidade Estadual do Rio de Janeiro Instituto de Matemática Departamento de Informática e Ciência da Computação Rio de Janeiro, agosto de

2 CONTEÚDO 0. INTRODUÇÃO 1. RECURSÃO 1.1 Conceitos básicos 1.2 Problemas clássicos 1.3 Análise da Recursão 1.4 Exercícios Propostos 2. BACKTRACKING 2.1 Conceitos básicos 2.2 Problemas clássicos 2.3 Jogos 2.4 Exercícios Propostos 3. PROGRAMAÇÃO DINÂMICA 3.1 Conceitos básicos 3.2 Problemas clássicos 3.3 Exercícios Propostos 4. MÉTODO GULOSO 4.1 Conceitos básicos 4.2 Problemas clássicos 4.3 Exercícios Propostos 5. PROBLEMAS NP-COMPLETOS 2

3 0. INTRODUÇÃO A ênfase deste curso é no estudo de uma ampla variedade de Algoritmos: métodos de solução de problemas adequados para implementação em computadores. Serão mostrados os problemas clássicos de cada método estudado, bem como uma visão simplificada da complexidade desses algoritmos. Sempre que possível serão também abordados problemas propostos nas diversas maratonas de programação da ACM. 0.1 Introdução à complexidade de Algoritmos - Notações O e Ω Duas características muito importantes dos algoritmos são o seu tempo de execução e a memória requerida. Quando se faz um algoritmo para resolver determinado problema, não basta que o algoritmo esteja correto. É importante que ele possa ser executado em um tempo razoável e dentro das restrições de memória existentes. Além disso, ele deve permanecer viável, à medida que o tempo passa, quando a quantidade de dados envolvida normalmente cresce. O estudo do comportamento dos algoritmos em termos do tempo de execução e memória, em função do crescimento dos dados envolvidos, denomina-se Complexidade de Algoritmos. Os parâmetros estudados normalmente são os seguintes: a) Complexidade de pior caso - caracterização do tempo de execuçãomáximo, para determinado tamanho da entrada, bem como das características da entrada que levam a esse tempo máximo. Este é o principal parâmetro para se avaliar um algoritmo. b) Complexidade de caso médio - caracterização do tempo de execução médio do algoritmo, para determinado tamanho da entrada, considerando a média de todas as possibilidades. Em muitas situações este parâmetro é útil. c) Complexidade de melhor caso - caracterização do tempo de execução mínimo, para determinado tamanho da entrada, bem como das características da entrada que levam a esse tempo mínimo. d) Memória requerida para se executar o algoritmo para determinado tamanho de entrada. A determinação da complexidade de pior caso teria que ser feita contando-se todas as instruções executadas e o tempo de execução de cada uma delas, considerando-se a pior entrada possível. Normalmente isso não é viável. O que se faz é determinar um limite superior para esse tempo, o mais próximo possível da realidade. Para tanto, fixa-se o estudo na instrução mais 3

4 executada do algoritmo e determina-se uma função t(n), que dá a variação do tempo de execução em função de n, o tamanho da entrada. O limite superior descrito anteriormente é definido pela conceituação O(t(n)), definida da seguinte forma: Sejam f, h duas funções reais positivas de variável inteira n. Diz-se que f é O(h), escrevendo-se f = O(h), quando existir uma constante c > 0 e um valor inteiro n 0, tal que n > n 0 => f(n) c.g(n). Exs: f = n 3 1 => f = O (n 3 ) = O (n 4 ) f = log n + 3 log 2 n => f = O (log 2 n ) Por convenção, os algoritmos que tenham complexidade de pior caso iguais ou inferiores a O(n k ) são considerados eficientes. Algoritmos cuja complexidade sejam, por exemplo, O(2 n ) são considerados ineficientes. Outro ponto importante é o seguinte: dado um problema, pode-se ter encontrado um algoritmo para resolvê-lo. Surge a pergunta se esse é o melhor algoritmo possível. Algumas vezes essa resposta pode ser obtida com a ajuda cos conceitos dados a seguir. Def: Dadas as funções sobre variáveis inteiras f e g. Dizemos que f é Ω (g), se existirem uma constante c e um número n 0 tal que f(n) c.g(n), para todo n > n 0. Se P é um problema, então dizemos que o limite inferior para P é dado por uma função h tal que a complexidade de pior caso de qualquer algoritmo que resolva P é Ω (h). Desta forma, quando conseguimos determinar o limite inferior para um problema e, ao mesmo tempo, conseguimos um algoritmo cuja complexidade de pior caso seja igual a esse limite, então estamos diante de um algoritmo ótimo, pois não se pode conseguir algoritmo com complexidade mais baixa que o mesmo. 4

5 0.2 Bibliografia recomendada Esta apostila está fortemente baseada no primeiro livro indicado abaixo e não pretende substituir um livro texto, necessário para se complementar a compreensão de cada tema abordado. Os seguintes livros são indicados: Algorithms R. Sedgewick;Addison-Wesley, 1988 Introduction To Algorithms T. H. Cormen et all; McGraw Hill, 1998 Estrut. de Dados e Seus Algoritmos J.L.Szwarcfiter, LTC 1994 Recomenda-se, também, o acesso aos seguintes sites que abordam problemas das maratonas de programação ACM e da Olimpíada de Informática:

6 1. RECURSÃO 1.1 Conceitos básicos Esta técnica de construção de algoritmos consiste basicamente em se subdividir um problema em problemas menores de mesma natureza que o problema original e obter a solução como uma composição das soluções dos problemas menores. Para a solução dos problemas menores adota-se a mesma estratégia de subdivisão, até o nível em que o subproblema seja muito simples, quando então sua solução é exibida, geralmente com poucos passos. A maneira de subdividir e de compor a solução pode ser diferente para cada caso. A seguir são mostrados dois exemplos clássicos de algoritmos recursivos: Fatorial e Fibonacci. O cálculo de fatorial tem a seguinte recursão: Fatorial (p): Início: Se (p = 0) Então Retornar 1 Senão Retornar p.fatorial(p-1); Fim; (A1.1) Nesta recursão o único problema resolvido diretamente é o de 0!. Os demais são resolvidos a partir da solução de cada problema imediatamente menor. Para a da série de Fibonacci, temos: Fibonacci(p): Início: Se (p 1) Então Retornar p Senão Retornar Fibonacci(p-1) + Fibonacci(p-2); Fim; (A1.2) 6

7 Há quatro outras visões sobre a técnica de recursão, que certamente complementam essa visão inicial: a) A técnica pode ser vista como uma maneira de se resolver problemas de "trás para frente", isto é: a solução enfatiza os passos finais para a solução do problema, supondo problemas menores resolvidos. No caso Fatorial, para se obter Fatorial(n), a idéia é multiplicar Fatorial (n-1) por n. b) A técnica pode ser ainda imaginada como o equivalente matemático da indução finita, onde, para se demonstrar fatos matemáticos usam-se duas etapas: b.1.1) Mostra-se que a hipótese vale para valores particulares e pequenos de n (0, 1, etc). b.1.2) Supondo-se a hipótese verdadeira para todos os valores inferiores a n, demonstra-se que ela continua valendo para n. Na recursão, temos que: b.2.1) Exibe-se um algoritmo para resolver casos particulares e pequenos (0, 1, etc). Os problemas pequenos são chamados problemas infantís. b.2.2) Exibe-se um algoritmo para achar a solução do problema grande a partir da composição de problemas menores. c) A técnica é o equivalente procedural da formulação de recorrências (funções recursivas), onde, de forma análoga ao ítem b), uma função é definida em duas partes. Na primeira, é dada uma fórmula fechada para um ou mais valores de n. Na segunda, a definição da função para n é feita a partir da mesma função aplicada a valores menores que n, para valores superiores aos da primeira parte. Outra relação de recursão com recorrência é que muitas propriedades de soluções recursivas são obtidas com o uso de recorrências. d) Os procedimentos recursivos são aqueles que "chamam a sí mesmo". É claro, então, que a chamada a sí mesmo sempre se dá no contexto de buscar a solução de problemas menores, para compor a solução do maior. Além disso todo procedimento recursivo tem que ter também uma chamada externa. Note que todo algoritmo recursivo tem uma solução não recursiva equivalente. Muitas vezes, entretanto, a expressão recursiva é mais natural e mais clara, como para os exemplos mostrados a seguir. 7

8 1.2 Problemas clássicos Neste tópico são apresentados os seguintes algoritmos clássicos com solução recursiva: a) Torre de Hanói b) Quicksort c) Mínimo e Máximo d) Cálculo de Combinação e) Torneio Torre de Hanói O problema baseia-se em um jogo infantil, onde há n pratos de tamanhos diferentes, com um furo no meio e três varetas A, B e C, que possibilitam que esses pratos possam ser empilhados em cada uma delas. O empilhamento só pode ser feito colocando-se pratos menores em cima de maiores. Inicialmente todos os pratos estão na vareta A. O problema é levar esses pratos para a vareta C, podendo usar as três varetas como empilhamento temporário. A B C Esse problema tem a seguinte solução recursiva: Hanoi(n, A, B, C); Início: Se (n > 0) Então Hanoi (n-1, A, C, B); Mover topo de A para C; Hanoi (n-1, B, A, C); Fim; (A1.3) Qualquer solução não recursiva para este problema é muito mais complicada que a mostrada acima. A complexidade desse algoritmo é O(2 n ), não sendo, portanto, um algoritmo eficiente. Entretanto isso é o melhor que pode ser feito, pois o problema é, em sí, exponencial (!). No exemplo, com os pratos numerados de 3 a 1, de baixo para cima, a solução seria: 8

9 Mover 1 de A p/ C; Mover 2 de A p/ B; Mover 1 de C para B; (Resolvido o problema para 2 pratos em B); Mover 3 de A para C; (Resolver novamente o problema de 2 pratos, só que p/ C): Mover 1 de B p/ A; Mover 2 de B p/ C; Mover 1 de A p/ C; Quicksort É considerado o melhor algoritmo de ordenação e foi um dos primeiros algoritmos recursivos propostos. A idéia é fazer, sucessivamente, partições em subvetores, de forma que a parte esquerda contenha sempre elementos menores ou iguais aos da direita. O problema simples é quando o tamanho de uma partição é 1. A partição baseia-se em escolher um elemento como um pivô, fazendo-se trocas para colocar maiores ou iguais de um lado e menores ou iguais do outro. Sort(E, D); Início: Se (D > E) Então Particao(E, D, I, J); Sort(E, J); Sort(I, D); Fim; (A1.4) Procedimento Particao (E, D, I, J) /* Baseada no elem. do meio */ Início: I E; J D; t A[ (E+D)/2 ]; Enquanto (I J): Enquanto (A[I] < t): I I + 1; Fe; Enquanto (t < A[J]): J J - 1; Fe; Se (I J) Então Troca_Elem(I, J); I I + 1; J J - 1; Fe; Fim; A seguir é dado um exemplo, mostrando os elementos envolvidos em comparações e trocas(estas indicadas em vermelho). Passo

10 E X E M P L O F A C I L E X E M P L O F A C I L Partição (1,12) 1 E L E I C A F O L P M X (1,7) (8,12) E L E I C A F Partição (1, 7) 2 E F E A C I L (1,5) (6,7) E F E A C Partição(1,5) 3 C A E F E (1,2) (3,3) (4,5) C A Partição (1,2) 4 A C (1,1) (2,2) F E Partição(4,5) 5 E F (4,4) (5,5) I L Partição(6,7) 6 I L (6,6) (7,7) O L P M X Partição(8,12) 7 O L M P X (8,10) (11,12) O L M Partição(8,10) 8 L O M (8,8) (9,10) O M Partição(9,10) 9 M O (9,9) (10,10) P X Partição(11,12) 10 P X (11,11) (12,12) A C E E F I L L M O P X Situação Final a) Análise do Algoritmo a.1) Complexidade: Melhor caso = Vetor Ordenado; NC =~nlog 2 n = O(n log 2 n) Pior caso = Há várias possibilidades. Vetor em Zig Zag, p. Ex. NC =~ n 2 /2 = O(n 2 ) Caso Médio: NC =~ nlog 2 n = O(n log 2 n) a.2) Estabilidade: Algoritmo não estável a.3) Situações Especiais: Algoritmo de uso amplo, extremamente rápido. a.4) Memória necessária: pilha de recursão (log 2 n). b) Observações: b.1) Número de comparações: 42 10

11 Número de trocas: 16 b.2) Este é um dos mais antigos e estudados algoritmos na Informática, tendo sido desenvolvido inicialmente por Hoare, em b.3) Notar o mecanismo de partição (1,5), (1,2) e (11,12). No primeiro caso, o subvetor é dividido em 3 partes (ao final J = 2, I = 4); no segundo caso, o vetor é subdividido em 2 partes (ao final J = 1, I = 2); no terceiro caso, o vetor também é subdvidido em 2 partes (mas ao final J = 10 (!?) e I = 12). O algoritmo tem complexidade O(n 2 ), pior que de alguns outros algoritmos de ordenação. Entretanto sua grande importância deriva do fato de o pior caso é algo raro de acontecer. A complexidade de caso médio é O(nlogn), e o algoritmo é muito rápido para o caso médio Mínimo e Máximo O problema é determinar os valores mínimo e máximo de um conjunto de números S. Esse problema tem uma solução trivial que é se fazer dois loops para encontrar separadamente os valores mínimo e máximo, executando exatamente 2n-2 comparações. O seguinte algoritmo recursivo permite uma melhora desse resultado: MinMax (S); Início: Seja S = [a 1,..., a n ] Se ( S = 1) Então Retornar (a 1, a 1 ); Senão Se ( S = 2) Então Se (a 1 > a 2 ) Então Retornar (a 2, a 1 ); Senão Retornar (a 1, a 2 ); Senão m Int( S /2); (b 1, c 1 ) MinMax(S 1 = [a 1,..., a m ]); (b 2, c 2 ) MinMax(S 2 = [a m+1,... a n ]); Retornar (min{ b 1, b 2 }, max{c1, c 2 }); Fim; (A1.5) Esta solução recursiva necessita apenas de (3n/2-2) comparações, mas a prova desse resultado fica como exercício. Esse resultado permite, então formular um algoritmo não recursivo com igual número de comparações, que é o seguinte: criam-se dois vetores, um de mínimos e outro de máximos. Esses vetores são preenchidos a partir da comparação, dois a dois, dos elementos 11

12 iniciais. O elemento perdedor vai para o vetor de mínimos e o vencedos, para o de máximos. Verifica-se, então, o menor dos mínimos e o maior dos máximos. O total de comparações, é então: n/2 + n/2-1 + n/2-1 3n/ Cálculo de Combinação O cálculo de número de combinações é simples, mas envolve um grande número de operações de multiplicação e divisão. Dependendo da ordem em que as operações são realizadas e da linguagem de implementação, pode-se facilmente "estourar" a capacidade numérica do ambiente e obter resultados errados. Isso acontece, por exemplo, no cálculo de Comb(50,2), se for implementada diretamente a fórmula clássica. A recursão fornece uma alternativa para algumas situações, bastando-se observar que Comb(n,p) = Comb(n,p-1)*(n-p+1)/p, o que sugere imediatamente a implementação a seguir: Comb(n, p); Início: Se (p = 1) Então Retornar n; Senão Retornar Comb(n, p-1)*(n-p+1)/p; Fim; (A1.6) Com essa implementação, muitas situações que dariam erro usando-se a fórmula clássica, passam a funcionar corretamente, como no caso do exemplo mencionado. A complexidade do algoritmo é O(p). Outra possibilidade é considerar Comb(n,p) = Comb(n-1,p)*n/(n-p), o que sugere a seguinte versão alternativa, com complexidade O(n): Comb(n, p); Início: Se (n = p) Então Retornar 1; Senão Retornar Comb(n-1, p)*n/(n-p); (A1.7) 12

13 Fim; Torneio Um problema de organização de torneios com n competidores, onde todos competidores jogam entre sí, é planejar as rodadas de forma que haja o menor número delas. Quando n é par, queremos que haja (n - 1) rodadas, e em cada rodada todos os times jogam. Quando n é impar então há n rodadas, sendo que em cada rodada jogam (n - 1) times e um deles fica "bye". Neste último caso, pode-se considerar que exista mais um time no grupo, que será considerado o emparelhamento "bye", de forma que admitiremos que haja sempre um número n par de competidores. Uma solução para o problema pode ser construir uma matriz R, n x n, onde a primeira coluna da matriz contenha os times e as colunas 2 a n, indiquem as rodadas de 1 a (n - 1). Cada elemento R(i, j) da matriz indica que R(i, j) é o adversário do time i na rodada j - 1. Vejamos um exemplo para n = 4. r 1 r 2 r 3 r Uma matriz R desse tipo tem as seguintes propriedades: a) R[i,1] i b) Todas as linhas são permutações dos elementos 1,2...n c) Todas as colunas são permutações dos elementos 1, 2...n d) Se j > 1, R[i,j] = t R[t,j] = i A essência do emparelhamento é expressa pela propriedade d). Este problema tem uma solução interessante recursiva quando n é potência de 2. O quadro abaixo ilustra a solução para n = 8: r 1 r 2 r 3 r 4 r 5 r 6 r 7 r

14 Pode-se observar a seguinte simetria nessa tabela: dividindo-a em 4 seções iguais, vê-se que a seção esquerda superior é igual à direita inferior e que a esquerda inferior é igual à direita superior. Além disso, a seção esquerda inferior corresponde à esquerda superior, somando-se n/2 aos números respectivos. Pode-se verificar que essa simetria é recursiva, quando se substitui um quadro pela seção esquerda superior, agora com número de elementos dividido por 2. O Esquema abaixo ilustra a composição recursiva: I III II IV A recursão é a seguinte: A matriz é dividida em 4 quadrantes iguais. O quadrantes I é preendhido recursivamente. Os demais quadrantes são assim obtidos: a) O quadrante II é copiado do quadrante I, com o acréscimo de n/2 a cada elemento. b) O quadrante III é uma cópia do II. c) O quadrante IV é uma cópia do I. A recursão se encerra quando se chega ao tamanho 1. Então é preenchido com o número 1. Notar que essa solução preserva as propriedades necessárias à matriz. Isso sugere o algoritmo a seguir, que usa uma matriz R n x n. m indica o tamanho da submatriz, Evidentemente, a chamada externa é: Torneio (n). Torneio (m): Início: (A1.8) 14

15 Fim; Se (m = 1) Então R[1,1] 1; Senão p m/2; Torneio(p); Para i de 1 até p: Para j de 1 até p: R[i + p, j] R[i, j] + p; R[i, j + p] R[i + p, j]; R[i + p, j + p] R[i, j]; Fp; Fp; O algoritmo tem, evidentemente, complexidade O(n 2 ). O argumento a seguir mostra que a recursão está correta, considerando-se que o problema esteja resolvido para o quadrante I. Realmente, a composição das soluções gera um conjunto de rodadas como o desejado, pois: a) nas n/2 rodadas finais, cada competidor da metade 1 compete com todos os competidores da metade 2 e vice-versa. b) em cada uma dessas rodadas participam todos os competidores, por construção da tabela. c) as atribuições dos jogos são coerentes, considerando-se as duas metades, também por construção simétrica da tabela. Para n potência de 2, este problema tem outra solução recursiva, levemente diferente da apresentada, que consiste do seguinte: a) preenche-se recursivamente o quadrante I. O problema elementar é como no caso anterior. b) O quadrante II é preenchido como no caso anterior. c) O quadrante III é preenchido com permutações circulares dos elementos do quadrante II. d) O quadrante IV é preenchido de forma forçada pelo preenchimento do quadranto III (ver a propriedade d necessária à matriz). A figura abaixo exemplifica a idéia. r 1 r 2 r 3 r 4 r 5 r 6 r 7 r

16 Finalmente, uma solução recursiva pode ser estabelecida para qualquer número de elementos, a partir da idéia deste último algoritmo. O número de rodadas será (n - 1) quando n for par ou n quando ímpar. Neste último caso pode-se imaginar que há um competidor adicional "bye", que participa dos emparelhamentos, de forma que podemos considerar o número de competidores um número par. Não há maiores dificuldades na recursão quando n é da forma n = 4k, para algum inteiro k, pois a solução acima aplica-se diretamente. A situação problemática é para números da forma: n = 4k + 2, porque, neste caso, a primeira metade da tabela tem tamanho n/2 x (n/2+1), o que geraria uma solução contendo n rodadas, que não é o objetivo perseguido. Vamos verificar, entretanto, que há uma forma de contornar esse incoveniente, eliminando uma das colunas dos quadrantes III e IV. 16

17 Torneio (m): (A1.8) Início: Se (m = 1) Então R[1, 1] 1 Senão Se (m ímpar) Então Torneio (m+1); Se (m = n) Então Considera o emparelhamento com (m+1) como bye ; Senão p m/2; Torneio (p); Se (p ímpar) Então q p + 1 Senão q p; Para i de 1 a p Para j de 1 a q: R[i + p, j] R[i, j] + p; Se (R[i + p, j] = m) Então R[i + p, 0] j; Fp; Para j de 1 até p: R[i, j + q] p (i + j 2) mod p; R[p (i + j 2) mod p, j + q] i; Fp; Fp; Se (p ímpar) Então Para i de 1 a ma: R[i, R[i, 0] ] R[i, q + 1]; Para j de (q + 1) a (q + p): R[i, j] R[i, j+1]; Fp; Fp; Fim; A recursão pode ser assim explicada: a) Se n for ímpar, resolve-se o problema para n+1 e, no final, abandonase a última linha e substitui-se o emparelhamento com o último número pelo emparelhamento bye. b) Resolve-se, recursivamente o problema para n/2. 17

18 c) Preenche-se os quadrantes II, III e IV conforme a segunda solução mostrada anteriormente para potências de 2, ou seja: o quadrante II é uma cópia do quadrante I, adicionando-se n/2 a todos os elementos. Caso o elemento seja bye, o correspondente também é tornado bye. O quadrante III é preenchido com permutações circulares dos números n/2+1 a n. O quadrante IV é preenchido de maneira forçada. d) Quando n é da forma n = 4k+2, temos alguns emparelhamentos bye indesejados nos quadrantes I e II, conforme descrito. Além disso a solução contém n rodadas. Mas podemos eliminar a primeira coluna dos quadrantes III e IV. Podemos observar que esta coluna contém os números com a seguinte ordenação: n/2+1, n/2+2...n, 1, 2,...n/2. Cada par (n/2+i, i), contendo um elemento do quadrante III e outro do quadrante IV, pode ser movido para a coluna do bye pois, pela simetria envolvida, essa coluna é a mesma para o par. Assim, consegue-se eliminar uma coluna e temos uma solução em n-1 rodadas, que era o objetivo inicial. Vejamos como se resolveria o problema para n = 5. Como 5 é ímpar, resolvemos o problema para n 1 = 6. Para tanto, começase fazendo a chamada recursiva para resolver o problema para n 2 = 3. Como 3 é ímpar, resolve-se o problema para n 3 = 4, que faz a chamada recursiva para n 4 = 2, com chamada para n 5 = 1 e depois obtendo: r 1 r A partir dessa solução, obtem-se sem dificuldade a solução para n 3 = 4: r 1 r 2 r 3 r Como o bojetivo era a solução para n 2 = 3, elimina-se a última linha e transforma-se o emparelhamento com 4 em emparelhamento bye, obtendo: r 1 r 2 r 3 r 4 18

19 Agora volta-se ao problema para n 1 = 6. Aplicando-se o procedimento mencionado, obtemos: r 1 r 2 r 3 r 4 r 5 r 6 r Como 6 é um número da forma 4k+2, temos uma solução indesejada em 6 rodadas. A seguir, move-se os pares (4, 1), (5, 2), (6, 3), da coluna r 5 para as colunas respectivas de bye e depois elimina-se essa coluna, redefinindo as colunas r 6 e r 7, finalizando a solução para n 1 = 6. r 1 r 2 r 3 r 4 r 5 r 6 r r 1 r 2 r 3 r 4 r 5 r

20 Para obter a solução final (n = 5), elimina-se a linha 6 e transforma-se os emparelhamentos com 6 para emparelhamentos bye, obtendo, então: r 1 r 2 r 3 r 4 r 5 r Um esboço do algoritmo é mostrado a seguir: Torneio (m); Início: Se (m = 1) Então R[1,1] 1; Senão Se (m ímpar) Então Torneio(m+1); Transforma emparelhamento com (m+1) em bye ; Senão Torneio (m/2); Copia Quadrante I p/ Quadrante II, acrescentando m/2; Gera permutação circular no quadrante III, para os elementos (m/2 + 1) a m; Preenche de maneira forçada o Quadrante IV; Se (m/2 ímpar) Então Move os elementos da coluna m/2+2 para a coluna de bye ; Move uma posição para a esquerda as colunas m/2+3 a m+1; Fim; 1.3 Análise da Recursão Serão apresentados três aspectos importantes para a análise do método de Recursão. O primeiro é o critério de balanceamento, que serve como orientação para se gerar bons programas recursivos, em geral. O segundo é uma ferramenta para análise da complexidade da recursão. O terceiro é uma ferramenta para evitar recursões ineficientes. 20

21 1.3.1 Balanceamento Um critério importante na sudivisão de um problema em problemas menores é o do Balanceamento: os problemas devem ter tamanhos iguais ou bem próximos, sob pena de se obter soluções ineficientes. Vejamos dois algoritmos distintos de ordenação: Mergesort e Bubblesort. O algoritmo Mergesort pode ser expresso pela recursão a seguir: Mergesort(E, D); Início: Se D > E Então m (E+D)/2 ; Mergesort(E, m); Mergesort(m+1, D); Merge (E, m, D); Fim; Chamada externa: Merge(1,n); (A1.9) No algoritmo Mergesort, cada problema de tamanho n foi dividido em dois subproblemas de tamanho aproximado n/2. A subdivisão é, pois, balanceada e a complexidade do algoritmo é O(nlogn). Já o algoritmo Bubblesort, pode ser expresso por: Bubblesort(m); Início: Se (m > 1) Então Para j de 1 a (m -1): Se (Vet[j] > Vet[j+1]) Então Troca(Vet[j], Vet[j+1]); Fp; Bubblesort(m -1); Fim; Chamada externa: Bubblesort(n); (A1.10) Neste caso, cada problema de tamanho n foi subdividido em dois problemas: um de tamanho 1 e outro de tamanho n-1. Para este algoritmo temos a complexidade O(n 2 ), ilustrando o fato de que o critério de balanceamento é algo positivo na recursão. 21

22 Quando um procedimento recursivo divide um problema grande em mais de um subproblema menor, a técnica costuma ser denominada Divisão e Conquista Árvore de recursão A análise da complexidade de algoritmos recursivos fica em geral facilitada quando se constrói a árvore de recursão das chamadas. No caso do algoritmo Fatorial, a árvore de recursão tem o seguinte aspecto: n n Como, em cada etapa da árvore é executada apenas uma instrução, a complexidade do algoritmo é equivalente ao número de nós da árvore (chamadas recursivas) que é O(n). Já no caso de Fibonacci, a árvore tem o seguinte aspecto: n n-1 n-2 n-2 n-3 n-3 n Como, em cada etapa da árvore é executada apenas uma instrução, a complexidade do algoritmo é igual ao número de nós da árvore que é O(2 n ), o que já torna este algoritmo inviável para valores de n bastante baixos (algo em torno de n = 30), qualquer que seja o computador utilizado! Para este algoritmo existe uma solução não recursiva trivial eficiente cuja complexidade é O(n). Basicamente o que está errado nessa solução é que o mesmo subproblema pode estar sendo resolvido milhares de vezes, à medida que se desce na árvore. A recorrência associada à série de Fibonacci é a seguinte: T(0) = 0 T(1) = 1 22

23 T(n) = T(n-1) + T(n-2) Podemos também criar uma recorrência que indica o número de chamadas recursivas da versão recursiva do algoritmo para Fibonacci: T(0) = 1 T(1) = 1 T(n) = 1 + T(n-1) + T(n-2) = 2*Fib(n+1) - 1. A solução dessa recorrência mostra que a complexidade do algoritmo é exponencial Memoization Para problemas como o anterior, cuja recorrência leve a uma complexidade exponencial, pode-se muitas vezes evitar essa complexidade através de uma técnica que tabele os resultados de chamadas intermediárias, de tal forma que a recursão para essas chamadas só ocorrerá uma vez. Nas demais, será utilizado um resultado encontrado em uma tabela apropriada. Consideremos o problema Moedas, cujo objetivo é o de determinar o número de possibilidades diferentes de gerar um troco no Brasil, utilizando apenas os 6 tipos de moedas de centavos existentes: 1 (R$ 0,01), 5 (R$0,05), 10 (R$0,10), 25 (R$0,25), 50 (R$0,50) e 100 (R$ 1). Expressaremos todos os valores em centavos, daquí por diante. Por exemplo, para dar um troco de 11 temos 4 possibilidades diferentes: ; 2 x 5 + 1; x 1; 11 x 1. Esse problema tem uma formulação recursiva, que pode ser estabelecida da seguinte maneira: Seja T(m,n) o número de possibilidades distintas de se gerar um troco de valor n, usando os m tipos iniciais de moedas. Inicialmente, supondo n > 100, podemos escrever: T(m,n) = T(1, n - 1) + T(2, n - 5) + T(3, n - 10) +...T(6, n - 100). O que pode ser assim entendido: A primeira parcela corresponde a se tomar as T(1, n - 1) maneiras distintas dar um troco para (n - 1) usando apenas a moeda de 1 centavo (neste caso T(1, n - 1) = 1, evidentemente). A segunda, T(2, n - 5) corresponde a se considerar os trocos possíveis para (n - 5) 23

24 centavos fixando-se sempre a primeira moeda como uma moeda de 5 e utilizando a solução para (n-5) com moedas de 1 e 5. De forma análoga para os demais. A parcela T(6, n - 100) corresponde aos tipos de troco que sempre tem uma moeda de 100, agregada às diversas possibilidades para trocos de (n - 100) centavos usando todos os tipos de moedas possíveis. Para completarmos a idéia recursiva, temos que estabelecer: T(m, 0) = 1 (pois só há uma maneira de dar troco 0). T(m, n) = 0, quando n < 0, pois não há troco negativo. A recursão, então, pode ser assim apresentada, considerando-se um vetor V[1..m], contendo os valores dos m (=6) tipos de moedas, em ordem crescente: V[1] 1; V[2] 5; V[3] 10; V[4] 25; V[5] 50; V[6] 100; T(m,n) 0, se n < 0; T(m,n) 1, se n = 0; T(m,n) Σ T(i, n - V[i]), n > 0, 1 i m. Não é preciso analisar muito para se perceber que essa formulação leva a um algoritmo exponencial. Entretanto, se criarmos uma matriz T, m x n, onde elemento da matriz tem o significado da recursão acima, podemos estabelecer o algoritmo abaixo, que tabela os resultados necessários na matriz, de forma que a recursão para cada par de valores só será chamada uma vez. O algoritmo é o seguinte: 24

25 Moedas (q, p); (A 1.11) Início: Se (p < 0) Então k 0; Senão Se (p = 0) Então k 1; Senão Se (T[q, p] = 0) Então k 0; Para i de 1 a q: k k + Moedas(i, p - V[i]); Fp; T[q, p] k; Senão k T[q, p]; Retornar (k); Fim; A tabela abaixo mostra quais subproblemas teriam que ser tabelados para n = 15; A tabela mostra que os seguintes subproblemas seriam tabelados: Todos os subproblemas T[1, i] para i < 15; Os subproblemas T[2, 0], T[2, 5], T[2, 10] O subproblema T[3, 5]; Desta forma, o algoritmo não é mais exponencial e passa a ser O(n 2 ). 25

26 1.4 Exercícios Propostos Escrever algoritmos recursivos para os problemas descritos a seguir (ALGOC) Quer-se fazer a geração de constantes numéricas usando apenas as seguintes operações: ONE - gera o número 1 MONE - gera o número -1 DUP - duplica o valor ADD - soma 1 ao valor (Maratona ACM América do Sul) (Nós mais distantes em uma árvore binária) Encontrar os dois nós mais distantes em uma árvore binária. (Se houver mais de um par listar todos os pares) (Algoritmo de Euclides) Encontrar o máximo divisor comum de dois números inteiros, usando a idéia do algoritmo de Euclides (Seleção 2 menores) Selecionar os dois menores elementos de um conjunto de n números (Busca por Faixa em Árvores Binárias de Busca) Mostrar todas as chaves de uma ABB, cujos valores situem-se dentro de uma faixa [c, f] dada (Desenho de árvore binária) Desenhar uma árvore binária, tal que a raiz apareça no centro da página, a raiz da subárvore esquerda no centro da metade esquerda da página, etc; (Caminho externo de AB) Calcular o tamanho do caminho externo de uma árvore binária (Radix Sort) Ordenar um conjunto de elementos, de forma análoga ao Quicksort, usando como critério de partição o valor do bit de dada posição (Cálculo de Potências) Calcular p n, onde n é um número inteiro. 26

27 (Desenho de aproximação de segmento) Desenhar uma aproximação do segmento de linha que une dois pontos de coordenadas (x 1, x 2 ) e (y 1, y 2 ) usando subsegmentos apenas de coordenadas inteiras (Pesquisa binária) Buscar um elemento em um vetor ordenado usando o critério de pesquisa binária (Problema de Josephus) Quer-se selecionar um elemento dentre n, numerados de 1 a n, que estão numa lista circular. A seleção é feita recebendo-se um inteiro p e fazendo-se a contagem circular de 1 a p eliminando-se, sucessivamente, da lista o elemento que recebeu a contagem p. Sempre que se elimina um elemento, a próxima contagem começa no elemento seguinte da lista. O selecionado é o último a sair (Fractais) Pesquisar algoritmos para desenhos de fractais. (Ver "Algorithms + Data Structures = Programs", de N. Wirth, Prentice_Hall, (Torneio) Fazer um algoritmo alternativo para Torneio, quando n é um quadrado perfeito. 27

28 2. BACKTRACKING 2.1 Conceitos básicos É um método organizado de se testar exaustivamente as possibilidades de configuração de objetos ou situações, em geral com o objetivo de escolher configurações com propriedades dadas. Um exemplo clássico é o algoritmo para se gerar todas as combinações p a p de n elementos. Este método é também usado para a implementação de jogos por computador, onde, em cada situação, este tem que escolher a melhor jogada dentre as normalmente inúmeras possíveis, sendo que essa escolha deve resultar do aprofundamento do exame das possíveis respostas do oponente, combinadas a novas jogadas etc. Diz-se que essa técnica é um método organizado de teste exaustivo, porque ela deve ser tal que descubra, o mais cedo possível, configurações inviáveis, o que pode levar ao abandono do exame de inúmeras situações inviáveis derivadas. Isso quer dizer que o método nem sempre examina exaustivamente as possibilidades, mas o abandono de certas possibilidades inviáveis só aumenta a eficiência do processo. Pode-se apresentar um algoritmo recursivo geral para esta idéia, que será denominado Config, expresso da seguinte forma: Config(); (A2.1) Início: Para cada elemento envolvido, efetuar: Se o elemento pode entrar na configuração, Então Colocar o elemento na configuração; Se a configuração tem a propriedade desejada Então Imprimir a configuração; Senão Config(); Retirar o elemento da configuração; Fim; Algumas observações sobre este modelo: 1) Evidentemente há uma chamada externa ao procedimento, normalmente precedida do esvaziamento da configuração. 2) O teste para descobrir se o elemento participa da configuração pode variar bastante de natureza, dependendo da situação. Quanto mais cedo se descobrir 28

29 elementos inviáveis na configuração, melhor, pois menor aprofundamento é necessário. 3) Grande parte das variáveis envolvidas pode ser de escopo global. 4) Muitas vezes pode ser necessário o uso de parâmetros na chamada recursiva. Inicialmente apresentamos um algoritmo para gerar permutações dos números 1 a n. O algoritmo usa um vetor P, inicialmente vazio, acrescentando, sucessivamente e de todas as maneiras, os números 1 a n em P, sem repetir. Perm; Início: Para i de 1 a n Se (i P) Então: P P + i; Se ( P = n) Então Imprimir P; Senão Perm(); P P - i; Fp; Fim; (A2.2) Externamente deve ser feito: P ; Perm; Uma forma mais diretamente implementável para o algoritmo acima utiliza uma variável externa para controlar o tamanho do vetor P (np) e um vetor booleano auxiliar para controlar testar se i P. Obtemos: Externamente deve ser feito: Para j de 1 a n: S[j] False; Fp; np 0; Perm; 29

30 Perm; Início: Para i de 1 a n Se (not S[i] ) Então: np np + 1; P[np] i; S[I] True; Se (np = n) Então Imprimir P; Senão Perm; np np - 1; S[I] False; Fp; Fim; (A2.2) Note a semelhança entre o algoritmo de Permutação e o modelo inicial apresentado para a técnica de Backtracking. Na verdade, o problema de gerar permutações é efetivamente um dos modelos básicos desta técnica, inclusive em termos de complexidade. Vê-se claramente que a complexidade deste algoritmo é O(n.n!), que não pode, entretanto, ser melhorada, já que o problema é, em sí, exponencial. Como esta técnica lança mão basicamente da recursão, temos também aquí a árvore de recursão de cada algoritmo. No caso do algoritmo de Permutação, se supusermos n = 5, ela tem a seguinte estrutura: Perm O número de folhas da árvore é 5! e cada caminho da raiz até uma das folhas obtem uma permutação diferente. De uma maneira geral, a árvore de recursão de backtracking tende a ser uma árvore do mesmo tipo da árvore de recursão de Permutação, onde o 30

31 número de possibilidades é exponencial. Isto esclarece a observação feita inicialmente de que é importante evitar possibilidades inviáveis, o mais cedo possível. Em termos da árvore de recursão, isso significa "podar" todo um ramo da árvore, sempre que se descobre uma inviabilidade em uma configuração parcial, o que leva a uma maior eficiência do algoritmo. No ítem relativo aos Jogos, algumas técnicas de "poda" serão explicadas. 2.2 Problemas clássicos Neste tópico são apresentados os seguintes algoritmos clássicos com solução por backtracking: a) Geração de combinações b) Damas pacíficas c) Torneio d) Geração de subconjuntos e) Soma de subconjuntos f) Partição aproximada 31

32 2.2.1 Geração de combinações As combinações t a t dos n elementos de um conjunto podem ser apresentadas em ordem lexicográfica. Uma forma de fazer isso é modificar a solução dada para a geração de permutações, colocando-se a restrição de que cada novo elemento só entra na configuração, se for maior que o último que entrou. Outra forma é utilizar um parâmetro que indica o valor mínimo dos elementos que podem entrar na configuração. Esse algoritmo é o seguinte: Comb(j); Início: Para i de j a n: nc nc + 1; P[nc] i; Se (nc = t) Então Imprimir P; Senão Comb(i+1); nc nc - 1; Fp; Fim; (A2.3) Externamente deve ser feito: nc 0; Comb(1); A complexidade do algoritmo acima, para valores baixos de p, é polinomial. Este algoritmo também ilustra o mecanismo de "poda" mencionado anteriormente. Se desenharmos a nova árvore de recursão e a compararmos com a anterior, para o caso de n = 5, temos várias podas a cada nível da árvore. 32

33 2.2.2 Damas pacíficas Este é um quebra-cabeças que utiliza os conceitos e o tabuleiro do jogo de xadrez. O objetivo é colocar 8 damas no tabuleiro, de forma que elas não se "ataquem", segundo as regras desse jogo. O exemplo abaixo ilustra uma das 92 possíveis soluções (das quais apenas 12 são soluções não simétricas): 1 R 2 R 3 R 4 R 5 R 6 R 7 R 8 R O seguinte algoritmo resolve esse problema: Damas_pacificas; Início: Para c de 1 até 8: Se (Permite(l+1, c)) Então l l + 1; TAB[l] c; Se (l = 8) Então Imprimir TAB; Senão Damas_pacificas; TAB[l] 0; l l -1 ; Fp; Fim; (A2.4) Externamente: Zerar TAB; l 0; Damas_pacificas(); Foi usada a função Permite(l, c) que verifica se é possível se colocar mais uma dama na posição (l, c), linha l, coluna c, sem atacar as demais (l -1). Notar que tanto o vetor quanto a variável l são globais. O algoritmo obtem todas as 33

34 92 soluções possíveis, mas poderia ser modificado para exibir apenas a primeira solução encontrada (!). Embora não seja dada a complexidade do algoritmo, ele também ilustra a explicação anterior sobre poda na árvore de recursão Torneio Podemos retornar ao problema de organização de torneios com n competidores, discutido no ítem O seguinte algoritmo resolve o problema: Torneio: Início: jog menor jogador não emparelhado na rodada; rod (NE+1)/n Para i de (jog+1) até n: Se (Pode_emparelhar(jog, i, rod)) Então NE NE+2; R[jog, rod] i; R[i, rod] jog; Se (NE = n 2 ) Então Imprime R; Senão Torneio; R[jog, rod] 0; R[i, rod] 0; NE NE - 2; Fp; Fim; (A2.5) Externamente: R[*,*] 0; Para j de 1 até n: R[j,1] j; Fp; NE n; Torneio(); Neste algoritmo R tem o mesmo significado que anteriormente, tanto que inicialmente faz-se com que a coluna 1 contenha os números 1 a n. Pode_emparelhar verifica se os parâmetros são diferentes e se já não foram emparelhados anteriormente (pode ser usada outra matriz para essa função). NE indica o número de emparelhamentos já realizados. A figura seguinte mostra um dos milhares de emparelhamentos obtido para n = 8: 34

35 c r 1 r 2 r 3 r 4 r 5 r 6 r O algoritmo gera todas as configurações possíveis mas pode ser modificado para gerar apenas uma delas, ou configurações com determinadas propriedades Geração de subconjuntos Muitos problemas envolvem a geração de alguns subconjuntos de dado conjunto. Vejamos inicialmente um modelo geral para a geração de subconjuntos de dado conjunto, mesmo sabendo que tal algoritmo tem complexidade exponencial, pois um conjunto com n elementos tem 2 n subconjuntos distintos. A idéia é se colocar os elementos do conjunto em uma lista C e se tomar, a cada passo um desses elementos, combinando com o mesmo todos os demais elementos à sua direita na lista. Isso fornece o algoritmo a seguir, que usa uma variável global ns e um vetor S que guarda o índice dos elementos do subconjunto: 35

36 Gera_subconjuntos (pi): Início: Para i de pi a n: ns ns + 1; S[ ns] i; Imprimir SubConj; Se (i < n) Então Gera_subconjuntos (i + 1); ns ns - 1; Fp; Fim; (A2.6) Externamente: ns 0; Gera_subconjuntos(1); Notar que no Backtracking acima simplificou-se, ligeiramente, o modelo geral, pois cada solução parcial é uma solução final e, além disso, também pode ser uma subsolução de uma outra. A sequência de subconjuntos gerada para o conjunto {a, b, c, d} seria: {a}, {a, b}, {a, b, c}, {a, b, c, d}, {a, b, d}, {a, c}, {a, c, d}, {a, d}, {b}, {b, c}, {b, c, d}, {b, d}, {c}, {c, d}, {d} Soma de subconjuntos Um problema interessante e que tem muitas variantes com aplicações práticas é o de, dado um conjunto C com n números inteiros, determinar se existe e quais combinações desses elementos têm soma igual a um valor s dado. Este problema é um caso particular de outro, muito famoso, denominado problema da Partição, que consiste em, dado um conjunto, determinar formas de particioná-lo em dois outros, tais que a soma dos elementos de cada partição seja a mesma. Ou seja, Soma de Subconjuntos é uma particularização de Partição, quando s não é a metade da soma dos elementos desse conjunto. Uma das possíveis soluções para soma de Subconjuntos é obtida da seguinte forma: ordenam-se os números e agrupam-se os mesmos de forma organizada, procurando obter o alvo s dado. Se, num dado ponto, a soma fica maior que s, o último elemento é abandonado, bem como todos aqueles maiores que o mesmo. O seguinte algoritmo resolve o problema: 36

37 Soma_subconjuntos(j): (A2.7) Início: i j; Enquanto (i n) e ((soma + C[i]) s): nr nr + 1; soma soma + C[i]; subconj[nr] i; Se (soma = s) Então Imprimir subconj; Senão Soma_subconjuntos(i+1); subconj[nr] 0; soma soma - C[i]; nr nr - 1; i i+1; Fe; Fim; Externamente: soma 0; nr 0; Ordena C; Soma_subconjuntos(1); O vetor subconj guarda os índices dos elementos que participam da soma desejada. Notar que foi utilizado um parâmetro na recursão. Notar, também a "poda" colocada no "loop" que pode fazer o algoritmo funcionar bem para valores pequenos de s. No caso não são gerados todos os subconjuntos, mas apenas aqueles que possam levar à solução do problema. Muitas possibilidades podem ser abandonadas o mais cedo possível Partição aproximada O problema mencionado anteriormente, Partição, nem sempre tem solução. Uma variante do mesmo, denominada Partição Aproximada, faz o particionamento do conjunto de forma a minimizar a diferença da soma entre as duas partições. Isso pode ser o melhor a se fazer em determinadas situações. O algoritmo a ser mostrado constitui-se um interessante paradigma de Backtracking onde a solução passa a ser buscada cada vez mais em subconjuntos restritos. O algoritmo a seguir é baseado no anterior, mas não se geram todos os subconjuntos. Apenas se examinam subconjuntos que tenham chance de melhorar uma solução prévia, caracterizada por dois parâmetros: dif = menor diferença entre partições já encontrada e msmp = maior soma da melhor partição já encontrada. A primeira solução considerada é uma partição 37

38 contendo um dos conjuntos nulos e o outro todos os elementos. Gradualmente vai-se obtendo soluções cada vez melhores e cada melhoria é armazenada, em substituição à melhor solução anteriormente. A melhor partição guardada é a solução e ela é exibida. O algoritmo é mostrado a seguir. Part_aproximada(pi): Início: i pi; Enquanto (i n) e ((soma + C[i] ) < msmp): nr nr + 1; soma soma + C[i]; Part[nr] i; Se (abs(tot 2*soma) < dif) Então Guarda; dif abs(tot 2*soma); msmp max(soma, tot - soma); Part_aproximada(i + 1); Part[nr] 0; soma soma - C[i]; nr nr - 1; i i+1; Fe; Fim; (A2.8) Externamente: soma 0; nr 0; tot ΣC[i]; dif tot; msmp tot; Ordena C; Part_aproximada(1); Imprime solução guardada; Neste algoritmo é chamado o procedimento Guarda, que armazena a melhor solução encontrada até o momento e atualiza o valor de dif. Se houver interesse em apenas uma solução, um mecanismo que pode parar a recursão é, quando a diferença (dif) atingir 0. Como exemplo, se tomarmos o conjunto {3, 4, 5, 7}, teremos a seguinte sequência de subconjuntos examinados e guardados: Guardados msmp dif {} {3} {3} {3, 4} {3, 4} 12 5 {3, 5} {3, 5} 11 3 {3, 7} {3, 7}

39 2.3 Jogos Uma das aplicações típicas da técnica de Backtracking é a programação de jogos, cujo desenvolvimento permitiu a utilização do método em vários outros tipos de problema. Considere jogos tais como xadrez, damas, jogo-davelha, onde há 2 jogadores. Os jogadores fazem jogadas alternadas e o estado do jogo pode ser representado pela posição do tabuleiro Árvore de jogo Suponha que há um número finito de configurações de tabuleiro e que o jogo tem uma regra de parada. A esse tipo de jogo pode-se associar uma árvore chamada "árvore do jogo". Cada nó representa uma posição do tabuleiro. A raiz é a situação inicial e cada nível da árvore contém as possíveis jogadas de um dos jogadores, de forma alternada. A árvore a seguir representa uma situação de decisão no jogo-da-velha, onde o computador tem que jogar. Suas jogadas são marcadas com "x", e as do oponente com "o": A (1) B (-1) C (0) o o x o (1) O computador joga x x D (0) E(-1) F (0) G (1) H (0) I (0) J (1) As possibilidades de continuação do jogo são as seguintes: A e J - o computador joga na linha 3 e ganha; B - o computador joga na linha do meio e o jogo continua C - o computador joga na linha 1 e o jogo continua D - o oponente joga na linha 3 e o jogo continua E - o oponente joga na linha 1 e ganha F - o oponente joga na linha 3 e o jogo continua G - o oponente joga na linha do meio e o jogo continua H - o computador joga na última linha e é empate I - o computador joga na linha do meio e é empate 39

40 Uma técnica para analisar o jogo consiste em atribuir às folhas 1 quando o computador ganha, 0 quando há empate ou -1 quando o oponente ganha. Esses valores podem ser propagados árvore acima, através do critério denominado MiniMax, que é o seguinte: cada nó pai recebe o valor máximo dos filhos quando é uma posição de jogada do computador, e o valor mínimo quando é uma posição de jogada do oponente. Esses números refletem a melhor estratégia para cada competidor. Quando for a vez do computador e o nó tiver valor 1, então há uma estratégia vencedora, dada por um caminho de valor 1 em todos os nós. Para jogos mais complicados, como o xadrez, por exemplo, a valoração dos nós assume uma gama mais ampla, podendo ir de 999 a 999, por exemplo, como será visto adiante. O algoritmo para o jogo consiste, portanto, em se construir a árvore, usando a ténica MiniMax e depois escolher a jogada usando a mesma. O cálculo dos valores dos nós pode ser feito pelo algoritmo seguinte, que basicamente é um percurso em pós-ordem na árvore de jogo, onde F representa um nó da árvore e Modo tem valor Min, quando o nó é de jogada do oponente ou Max, quando é de jogada do computador: Avalia_no (F, Modo); (A2.9) Início: Se (F é folha) Então Retornar (Calcula_valor(F)); Senão Se (Modo = Max) Então Valor - ; Senão Valor ; Para cada filho w de F: Se (Modo = Max) Então Valor Max (Valor, Avalia_no(w, Min)); Senão Valor Min (Valor, Avalia_no(w, Max)); Retornar Valor Fim; A função Calcula_valor avalia o valor da posição final do jogo. A constante Infinito representa o maior valor inteiro que pode ser representado. 40

41 2.3.2 Poda Heurística Alguns jogos, entretanto, têm um número de alternativas absurdamente grande, o que inviabiliza a construção e exame de toda a árvore. As folhas muitas vezes representarão apenas configurações parciais do jogo. No caso do xadrez a ordem de grandeza do número de folhas é O que se faz, então é a introdução de Heurísticas para avaliação de posições do tabuleiro, somente aprofundando a análise de situações mais críticas e aplicando o método MiniMax para a árvore "podada" obtida e considerando, agora, que a valoração poderá variar numa gama mais ampla do que a vista para o jogo da velha, já que não se pode mais aplicar o critério absoluto de posição perdida/ganha/empatada, uma vez que a avaliação não parte dos nós finais. A perícia de um jogo para xadrez reside, portanto, na qualidade das heurísticas utilizadas. A avaliação heurística de uma configuração do tabuleiro é empírica, levando em conta o balanço ponderado das peças presentes e o valor de elementos estratégicos e táticos. O sucesso desse tipo de programa evidencia que existem boas heurísticas para a situação. Entretanto fica também evidente que nenhum programa é imbatível por um ser humano, visto que o programa não joga de forma exata. Quando se usa poda heurística, a cada jogada é construída uma nova árvore, que só é usada para a decisão do próximo lance Poda alfa_beta Uma das melhorias que podem ser introduzidas no método MiniMax é denominada poda Alfa_beta, que permite abandonar o exame de trechos da árvore. Seja a situação abaixo da árvore de jogo: Max x Min f 1 (120) f 2 ( 32) f 3 h 1 (32) Suponha que se acabou de determinar o valor do nó f 1, depois de percorrer a sub-árvore correspondente. Quando se começa a examinar a subárvore do nó irmão f 2 e se descobre que o valor do primeiro filho é 32, pode-se abandonar todo o exame de f 2, atribuindo a esse nó o valor aproximado 32, já que o mesmo não vai influenciar no cálculo de x, pois f 2 tem o valor limitante

42 De forma análoga à descrita, o exame de muitos trechos da árvore pode ser abandonado, tornando sua avaliação mais rápida. Na realidade, a construção da árvore pode ser simultânea à avaliação, o que significa que pode não ser necessária a construção de toda a árvore do jogo. Dessa forma a poda Alfa-beta pode tornar o jogo mais eficiente. 42

Backtracking. Backtracking

Backtracking. Backtracking Notas de aula da disciplina IME 0-0 ALGORITMOS E ESTRUTURAS DE DADOS II Paulo Eustáquio Duarte Pinto (pauloedp arroba ime.uerj.br) É uma técnica de solução de problemas (construção de algoritmos) que eamina

Leia mais

Introdução à Análise Algoritmos

Introdução à Análise Algoritmos Introdução à Análise Algoritmos Notas de aula da disciplina IME 4-182 Estruturas de Dados I Paulo Eustáquio Duarte Pinto (pauloedp arroba ime.uerj.br) abril/218 Ordenação por SELEÇÃO: Idéia: Dado um vetor

Leia mais

Introdução Paradigmas

Introdução Paradigmas Introdução Paradigmas Recursividade Algoritmos tentativa e erro Divisão e conquista Programação dinâmica Algoritmos gulosos Algoritmos aproximados 1 Introdução O projeto de algoritmos requer abordagens

Leia mais

Análise e Complexidade de Algoritmos

Análise e Complexidade de Algoritmos Análise e Complexidade de Algoritmos Principais paradigmas do projeto de algoritmos - Recursividade - Tentativa e erro - Divisão e Conquista - Programação dinâmica - Algoritmos Gulosos e de Aproximação

Leia mais

Estruturas de Dados, Análise de Algoritmos e Complexidade Estrutural. Carlos Alberto Alonso Sanches

Estruturas de Dados, Análise de Algoritmos e Complexidade Estrutural. Carlos Alberto Alonso Sanches CT-234 Estruturas de Dados, Análise de Algoritmos e Complexidade Estrutural Carlos Alberto Alonso Sanches CT-234 2) Algoritmos recursivos Indução matemática, recursão, recorrências Indução matemática Uma

Leia mais

Projeto e Análise de Algoritmos Aula 4: Dividir para Conquistar ou Divisão e Conquista ( )

Projeto e Análise de Algoritmos Aula 4: Dividir para Conquistar ou Divisão e Conquista ( ) Projeto e Análise de Algoritmos Aula 4: Dividir para Conquistar ou Divisão e Conquista (2.1-2.2) DECOM/UFOP 2013/1 5º. Período Anderson Almeida Ferreira Adaptado do material desenvolvido por Andréa Iabrudi

Leia mais

Algoritmos de Ordenação

Algoritmos de Ordenação Algoritmos de Ordenação Introdução à Ciência da Computação Prof. Edison Ishikawa Objetivo Apresentar diferentes algoritmos de ordenação de dados Mostrar como analisar os algoritmos em termos de tempo de

Leia mais

Jogos. Geralmente o oponente tentará, na medida do possível, fazer o movimento menos benéfico para o adversário.

Jogos. Geralmente o oponente tentará, na medida do possível, fazer o movimento menos benéfico para o adversário. Jogos Os jogos tem atraído a atenção da humanidade, às vezes de modo alarmante, desde a antiguidade. O que o torna atraente para a IA é que é uma abstração da competição (guerra), onde se idealizam mundos

Leia mais

Método Guloso. Troco mínimo. Paulo Eustáquio Duarte Pinto (pauloedp arroba ime.uerj.br) junho/2012. Troco mínimo. Troco mínimo

Método Guloso. Troco mínimo. Paulo Eustáquio Duarte Pinto (pauloedp arroba ime.uerj.br) junho/2012. Troco mínimo. Troco mínimo Notas de aula da disciplina IME - ALGORITMOS E ESTRUTURAS DE DADOS II Paulo Eustáquio Duarte Pinto (pauloedp arroba ime.uerj.br) Troco mínimo Dados os tipos de moedas de um país, determinar o número mínimo

Leia mais

É interessante comparar algoritmos para valores grandes de n. Para valores pequenos de n, mesmo um algoritmo ineficiente não custa muito para ser

É interessante comparar algoritmos para valores grandes de n. Para valores pequenos de n, mesmo um algoritmo ineficiente não custa muito para ser É interessante comparar algoritmos para valores grandes de n. Para valores pequenos de n, mesmo um algoritmo ineficiente não custa muito para ser executado 1 Fazendo estimativas e simplificações... O número

Leia mais

Algoritmos de Ordenação

Algoritmos de Ordenação Algoritmos de Ordenação! Problema: encontrar um número de telefone em uma lista telefônica! simplificado pelo fato dos nomes estarem em ordem alfabética! e se estivesse sem uma ordem?! Problema: busca

Leia mais

Técnicas de análise de algoritmos

Técnicas de análise de algoritmos CENTRO FEDERAL DE EDUCAÇÃO TECNOLÓGICA DE MINAS GERAIS Técnicas de análise de algoritmos Algoritmos e Estruturas de Dados I Natália Batista https://sites.google.com/site/nataliacefetmg/ nataliabatista@decom.cefetmg.br

Leia mais

Análise e Complexidade de Algoritmos

Análise e Complexidade de Algoritmos Análise e Complexidade de Algoritmos Professor Ariel da Silva Dias Algoritmos Divisão e Conquista Construção incremental Resolver o problema para um sub-conjunto dos elementos de entrada; Então, adicionar

Leia mais

Complexidade de Algoritmos

Complexidade de Algoritmos Complexidade de Algoritmos O que é um algoritmo? Sequência bem definida e finita de cálculos que, para um dado valor de entrada, retorna uma saída desejada/esperada. Na computação: Uma descrição de como

Leia mais

Lista 1 - PMR2300. Fabio G. Cozman 3 de abril de 2013

Lista 1 - PMR2300. Fabio G. Cozman 3 de abril de 2013 Lista 1 - PMR2300 Fabio G. Cozman 3 de abril de 2013 1. Qual String é impressa pelo programa: p u b l i c c l a s s What { p u b l i c s t a t i c void f ( i n t x ) { x = 2 ; p u b l i c s t a t i c void

Leia mais

Análise de algoritmos

Análise de algoritmos Análise de algoritmos Introdução à Ciência de Computação II Baseados nos Slides do Prof. Dr. Thiago A. S. Pardo Análise de algoritmos Existem basicamente 2 formas de estimar o tempo de execução de programas

Leia mais

Algoritmos e Estruturas de Dados I Linguagem C

Algoritmos e Estruturas de Dados I Linguagem C Algoritmos e Estruturas de Dados I (DCC/003) Algoritmos e Estruturas de Dados I Linguagem C Aula Tópico 11 Recursividade 1 Recursão Na linguagem C, uma função pode chamar outra função. A função main()

Leia mais

Projeto e Análise de Algoritmos

Projeto e Análise de Algoritmos Projeto e Algoritmos Pontifícia Universidade Católica de Minas Gerais harison@pucpcaldas.br 26 de Maio de 2017 Sumário A complexidade no desempenho de Quando utilizamos uma máquina boa, ela tende a ter

Leia mais

Otimização Combinatória - Parte 4

Otimização Combinatória - Parte 4 Graduação em Matemática Industrial Otimização Combinatória - Parte 4 Prof. Thiago Alves de Queiroz Departamento de Matemática - CAC/UFG 2/2014 Thiago Queiroz (DM) Parte 4 2/2014 1 / 33 Complexidade Computacional

Leia mais

Busca Competitiva. Inteligência Artificial. Até aqui... Jogos vs. busca. Decisões ótimas em jogos 9/22/2010

Busca Competitiva. Inteligência Artificial. Até aqui... Jogos vs. busca. Decisões ótimas em jogos 9/22/2010 Inteligência Artificial Busca Competitiva Aula 5 Profª Bianca Zadrozny http://www.ic.uff.br/~bianca/ia-pos Capítulo 6 Russell & Norvig Seção 6.1 a 6.5 2 Até aqui... Problemas sem interação com outro agente.

Leia mais

Estruturas de Dados 2

Estruturas de Dados 2 Estruturas de Dados 2 Técnicas de Projeto de Algoritmos Dividir e Conquistar IF64C Estruturas de Dados 2 Engenharia da Computação Prof. João Alberto Fabro - Slide 1/83 Projeto de Algoritmos por Divisão

Leia mais

Aula 1. Teoria da Computação III

Aula 1. Teoria da Computação III Aula 1 Teoria da Computação III Complexidade de Algoritmos Um problema pode ser resolvido através de diversos algoritmos; O fato de um algoritmo resolver um dado problema não significa que seja aceitável

Leia mais

Classes, Herança e Interfaces

Classes, Herança e Interfaces Escola de Artes, Ciências e Humanidades EACH-USP ACH2002 Introdução à Ciência da Computação II Professor: Delano Medeiros Beder revisada pelo professor: Luciano Digiampietri EACH Segundo Semestre de 2011

Leia mais

Recursividade. Objetivos do módulo. O que é recursividade

Recursividade. Objetivos do módulo. O que é recursividade Recursividade Objetivos do módulo Discutir o conceito de recursividade Mostrar exemplos de situações onde recursividade é importante Discutir a diferença entre recursividade e iteração O que é recursividade

Leia mais

Métodos de Ordenação Parte I

Métodos de Ordenação Parte I Estrutura de Dados II Métodos de Ordenação Parte I Prof a Márcio Bueno ed2tarde@marciobueno.com / ed2noite@marciobueno.com Material baseado nos materiais da Prof a Ana Eliza e Prof. Robson Lins Rearranjar

Leia mais

ALGORITMOS DE ORDENAÇÃO

ALGORITMOS DE ORDENAÇÃO ALGORITMOS DE ORDENAÇÃO Prof. André Backes Conceitos básicos 2 Ordenação Ato de colocar um conjunto de dados em uma determinada ordem predefinida Fora de ordem 5, 2, 1, 3, 4 Ordenado 1, 2, 3, 4, 5 OU 5,

Leia mais

Prof. A. G. Silva. 25 de setembro de Prof. A. G. Silva INE5603 Introdução à POO 25 de setembro de / 35

Prof. A. G. Silva. 25 de setembro de Prof. A. G. Silva INE5603 Introdução à POO 25 de setembro de / 35 INE5603 Introdução à POO Prof. A. G. Silva 25 de setembro de 2017 Prof. A. G. Silva INE5603 Introdução à POO 25 de setembro de 2017 1 / 35 Baseado em materiais da Recursividade Unisinos, Cesar Tacla (UTFPR),

Leia mais

Modelagem com relações de recorrência. Exemplo: Determinada população dobra a cada ano; população inicial = 5 a n = população depois de n anos

Modelagem com relações de recorrência. Exemplo: Determinada população dobra a cada ano; população inicial = 5 a n = população depois de n anos Relações de recorrência 8. RELAÇÕES DE RECORRÊNCIA Introdução a relações de recorrência Modelagem com relações de recorrência Solução de relações de recorrência Exemplos e aplicações Relações de recorrência

Leia mais

Programação Estruturada

Programação Estruturada Programação Estruturada Recursão Professores Emílio Francesquini e Carla Negri Lintzmayer 2018.Q3 Centro de Matemática, Computação e Cognição Universidade Federal do ABC Recursão Recursão 1 Recursão 2

Leia mais

Paradigmas de Projetos de Algoritmos

Paradigmas de Projetos de Algoritmos Paradigmas de Projetos de Algoritmos Luciana Assis 9 de junho de 2016 Luciana Assis (UFVJM) 9 de junho de 2016 1 / 36 1 Introdução 2 Força Bruta 3 Abordagem Incremental ou Construtiva 4 Recursão 5 Divisão

Leia mais

SCC Capítulo 2 Recursão

SCC Capítulo 2 Recursão SCC-501 - Capítulo 2 João Luís Garcia Rosa 1 1 Departamento de Ciências de Computação Instituto de Ciências Matemáticas e de Computação Universidade de São Paulo - São Carlos http://www.icmc.usp.br/~joaoluis

Leia mais

Análise de Algoritmos Estrutura de Dados II

Análise de Algoritmos Estrutura de Dados II Centro de Ciências Exatas, Naturais e de Saúde Departamento de Computação Análise de Algoritmos Estrutura de Dados II COM10078 - Estrutura de Dados II Prof. Marcelo Otone Aguiar marcelo.aguiar@ufes.br

Leia mais

Lista de exercícios sobre contagem de operações Prof. João B. Oliveira

Lista de exercícios sobre contagem de operações Prof. João B. Oliveira Lista de exercícios sobre contagem de operações Prof. João B. Oliveira 1. metodo m ( Vetor V ) int i, res = 0; para i de 1 a V.size res = res + V[i]; return res; Soma de elementos de um vetor, O( ). 2.

Leia mais

AED2 - Aula 11 Problema da separação e quicksort

AED2 - Aula 11 Problema da separação e quicksort AED2 - Aula 11 Problema da separação e quicksort Projeto de algoritmos por divisão e conquista Dividir: o problema é dividido em subproblemas menores do mesmo tipo. Conquistar: os subproblemas são resolvidos

Leia mais

Algoritmos e Estruturas de Dados I

Algoritmos e Estruturas de Dados I Algoritmos e Estruturas de Dados I Prof. Daniel M. Martin (daniel.martin@ufabc.edu.br) Aula 10 (Baseada nos slides do Prof. André Balan) Recursão Recursão Da wikipedia: A recursão é o processo pelo qual

Leia mais

ALGORITMOS AVANÇADOS UNIDADE II Recursividade. Luiz Leão

ALGORITMOS AVANÇADOS UNIDADE II Recursividade. Luiz Leão Luiz Leão luizleao@gmail.com http://www.luizleao.com Conteúdo Programático 2.1 - Definições recursivas 2.2 - Como implementar recursividade 2.3 - Quando não usar recursividade 2.4 - Desenvolvendo algoritmos

Leia mais

Exercícios: Vetores e Matrizes

Exercícios: Vetores e Matrizes Universidade Federal de Uberlândia - UFU Faculdade de Computação - FACOM Lista de exercícios de programação em linguagem C Exercícios: Vetores e Matrizes 1 Vetores 1. Faça um programa que possua um vetor

Leia mais

5ª Lista de Exercícios de Programação I

5ª Lista de Exercícios de Programação I 5ª Lista de Exercícios de Programação I Instrução As questões devem ser implementadas em C. Questões que envolvam leitura de matrizes, a construção dessas matrizes pode ser realizada através da geração

Leia mais

ANÁLISE DE ALGORITMOS

ANÁLISE DE ALGORITMOS ANÁLISE DE ALGORITMOS Paulo Feofiloff Instituto de Matemática e Estatística Universidade de São Paulo agosto 2009 Introdução P. Feofiloff (IME-USP) Análise de Algoritmos agosto 2009 2 / 102 Introdução

Leia mais

Cálculo Numérico BCC760

Cálculo Numérico BCC760 Cálculo Numérico BCC760 Resolução de Sistemas de Equações Lineares Simultâneas Departamento de Computação Página da disciplina http://www.decom.ufop.br/bcc760/ 1 Introdução! Definição Uma equação é dita

Leia mais

Introdução à Ciência da Computação II

Introdução à Ciência da Computação II Introdução à Ciência da Computação II 2semestre/200 Prof Alneu de Andrade Lopes Apresentação com material gentilmente cedido pelas profas Renata Pontin Mattos Fortes http://wwwicmcuspbr/~renata e Graça

Leia mais

Aulas 5 e 6 / 28 e 30 de março

Aulas 5 e 6 / 28 e 30 de março Aulas 5 e / 8 e 30 de março 1 Notação de soma e produto Como expressar a seguinte soma de uma maneira mais concisa? 1 + + 3 3 + + 10? Note que as parcelas são semelhantes, e que a única coisa que varia

Leia mais

Projeto e Análise de Algoritmos

Projeto e Análise de Algoritmos Projeto e Análise de Algoritmos Aula 01 Complexidade de Algoritmos Edirlei Soares de Lima O que é um algoritmo? Um conjunto de instruções executáveis para resolver um problema (são

Leia mais

BCC402 Algoritmos e Programação Avançada Prof. Marco Antonio M. Carvalho Prof. Túlio Ângelo M. Toffolo 2011/1

BCC402 Algoritmos e Programação Avançada Prof. Marco Antonio M. Carvalho Prof. Túlio Ângelo M. Toffolo 2011/1 BCC402 Algoritmos e Programação Avançada Prof. Marco Antonio M. Carvalho Prof. Túlio Ângelo M. Toffolo 2011/1 Na aula anterior Prova 2 Na aula de hoje Técnicas básicas de contagem; Tentativa e Erro; Recursividade.

Leia mais

Árvores. Thiago Martins, Fabio Gagliardi Cozman. PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo

Árvores. Thiago Martins, Fabio Gagliardi Cozman. PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo PMR2300 / PMR3201 Escola Politécnica da Universidade de São Paulo Árvore: estrutura composta por nós e arestas entre nós. As arestas são direcionadas ( setas ) e: um nó (e apenas um) é a raiz; todo nó

Leia mais

Recursividade, Tentativa e Erro

Recursividade, Tentativa e Erro Recursividade, Tentativa e Erro Túlio Toffolo www.toffolo.com.br Marco Antônio Carvalho marco.opt@gmail.com BCC402 Aula 07 Algoritmos e Programação Avançada Na aula anterior Prova 2 Na aula de hoje Técnicas

Leia mais

Aula 06: Análise matemática de algoritmos recursivos

Aula 06: Análise matemática de algoritmos recursivos Aula 06: Análise matemática de algoritmos recursivos David Déharbe Programa de Pós-graduação em Sistemas e Computação Universidade Federal do Rio Grande do Norte Centro de Ciências Exatas e da Terra Departamento

Leia mais

Estruturas de Dados 2

Estruturas de Dados 2 Estruturas de Dados 2 Algoritmos de Ordenação em Tempo Linear IF64C Estruturas de Dados 2 Engenharia da Computação Prof. João Alberto Fabro - Slide 1/38 Algoritmos de Ordenação em Tempo Linear Limite Assintótico

Leia mais

ALGORITMOS AVANÇADOS UNIDADE I Análise de Algoritmo - Notação O. Luiz Leão

ALGORITMOS AVANÇADOS UNIDADE I Análise de Algoritmo - Notação O. Luiz Leão Luiz Leão luizleao@gmail.com http://www.luizleao.com Conteúdo Programático 1.1 - Algoritmo 1.2 - Estrutura de Dados 1.2.1 - Revisão de Programas em C++ envolvendo Vetores, Matrizes, Ponteiros, Registros

Leia mais

5. Algoritmos de Ordenação

5. Algoritmos de Ordenação Introdução à Computação II 5952011 5. Algoritmos de Ordenação Prof. Renato Tinós Depto. de Computação e Matemática (FFCLRP/USP) 1 Principais Tópicos 5.1. Ordenação por Inserção 5.2. Ordenação por Seleção

Leia mais

Técnicas de Projeto de Algoritmos

Técnicas de Projeto de Algoritmos UNIVERSIDADE NOVE DE JULHO - UNINOVE Pesquisa e Ordenação Técnicas de Projeto de Algoritmos Material disponível para download em: www.profvaniacristina.com Profa. Vânia Cristina de Souza Pereira 03 _ Material

Leia mais

Os métodos de ordenação que ordenam os elementos in situ podem ser classificados em três principais categorias:

Os métodos de ordenação que ordenam os elementos in situ podem ser classificados em três principais categorias: ORDENAÇÃO A atividade de ordenação é o processo de rearranjo de um certo conjunto de objetos de acordo com um critério (ordem) específico. O objetivo da ordenação é facilitar a localização dos membros

Leia mais

Algoritmos e Estruturas de Dados I 01/2013. Vetores e Recursividade. Pedro O.S. Vaz de Melo

Algoritmos e Estruturas de Dados I 01/2013. Vetores e Recursividade. Pedro O.S. Vaz de Melo Algoritmos e Estruturas de Dados I 01/2013 Vetores e Recursividade Pedro O.S. Vaz de Melo Problema 1 Implemente uma função que classifique os elementos de um vetor em ordem crescente usando o algoritmo

Leia mais

Medida do Tempo de Execução de um Programa. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Medida do Tempo de Execução de um Programa. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR Medida do Tempo de Execução de um Programa David Menotti Algoritmos e Estruturas de Dados II DInf UFPR Classes de Comportamento Assintótico Se f é uma função de complexidade para um algoritmo F, então

Leia mais

Hashing: conceitos. Hashing

Hashing: conceitos. Hashing Hashing: conceitos hashing é uma técnica conhecida como espalhamento, mapeamento ou randomização que tenta distribuir dados em posições aleatórias de uma tabela (array) associa cada objeto (de um determinado

Leia mais

Análise de complexidade

Análise de complexidade Introdução Algoritmo: sequência de instruções necessárias para a resolução de um problema bem formulado (passíveis de implementação em computador) Estratégia: especificar (definir propriedades) arquitectura

Leia mais

ANÁLISE DE COMPLEXIDADE DOS ALGORITMOS

ANÁLISE DE COMPLEXIDADE DOS ALGORITMOS 1/18 ANÁLISE DE COMPLEXIDADE DOS ALGORITMOS Algoritmos 2/18 Algoritmos Algoritmo - sequência de instruções necessárias para a resolução de um problema bem formulado (passíveis de implementação em computador)

Leia mais

Divisão e conquista. Eficiência de divisão e conquista

Divisão e conquista. Eficiência de divisão e conquista Divisão e conquista Divisão: resolver recursivamente problemas mais pequenos (até caso base) Conquista: solução do problema original é formada com as soluções dos subproblemas á divisão quando o algoritmo

Leia mais

BCC204 - Teoria dos Grafos

BCC204 - Teoria dos Grafos BCC204 - Teoria dos Grafos Marco Antonio M. Carvalho (baseado nas notas de aula do prof. Haroldo Gambini Santos) Departamento de Computação Instituto de Ciências Exatas e Biológicas Universidade Federal

Leia mais

Utilização do Conjunto de Cantor para a resolução da Torre de Hanoi

Utilização do Conjunto de Cantor para a resolução da Torre de Hanoi Utilização do Conjunto de Cantor para a resolução da Torre de Hanoi Filipe Daniel Lemos FEUP 030509045 Dezembro de 2004 Resumo Segundo trabalho para a cadeira de Física dos sitemas dinâmicos do curso de

Leia mais

Aula prática 5. Funções Recursivas

Aula prática 5. Funções Recursivas Programação Funcional UFOP DECOM 2014.1 Aula prática 5 Funções Recursivas Resumo Definições recursivas são comuns na programação funcional. Nesta aula vamos aprender a definir funções recursivas. Sumário

Leia mais

Comparação com Divisão e Conquista

Comparação com Divisão e Conquista Programação Dinâmica Programação Dinâmica Fernando Lobo Algoritmos e Estrutura de Dados II Outra técnica de concepção de algoritmos, tal como Divisão e Conquista ou Estratégias Greedy. O termo Programação

Leia mais

Árvore Binária de Busca Ótima

Árvore Binária de Busca Ótima MAC 5710 - Estruturas de Dados - 2008 Referência bibliográfica Os slides sobre este assunto são parcialmente baseados nas seções sobre árvore binária de busca ótima do capítulo 4 do livro N. Wirth. Algorithms

Leia mais

O termo Programação Dinâmica é um bocado infeliz.

O termo Programação Dinâmica é um bocado infeliz. Programação Dinâmica Fernando Lobo Algoritmos e Estrutura de Dados II 1 / 18 Programação Dinâmica Outra técnica de concepção de algoritmos, tal como Divisão e Conquista ou Estratégias Greedy. O termo Programação

Leia mais

Marina Andretta. 10 de outubro de Baseado no livro Introduction to Linear Optimization, de D. Bertsimas e J. N. Tsitsiklis.

Marina Andretta. 10 de outubro de Baseado no livro Introduction to Linear Optimization, de D. Bertsimas e J. N. Tsitsiklis. Solução básica viável inicial Marina Andretta ICMC-USP 10 de outubro de 2016 Baseado no livro Introduction to Linear Optimization, de D. Bertsimas e J. N. Tsitsiklis. Marina Andretta (ICMC-USP) sme0211

Leia mais

Lista 2 - PMR2300/3200

Lista 2 - PMR2300/3200 Lista 2 - PMR2300/3200 Fabio G. Cozman, Thiago Martins 8 de março de 2015 1. Qual String é impressa pelo programa: p u b l i c c l a s s What { p u b l i c s t a t i c void f ( i n t x ) { x = 2 ; p u

Leia mais

Lista 1. 8 de abril de Algorithms: Capítulo 0, exercícios 1 e 2. Tardos: Todos exercícios do cap 2 do livro texto, exceto 7 e 8 letra b.

Lista 1. 8 de abril de Algorithms: Capítulo 0, exercícios 1 e 2. Tardos: Todos exercícios do cap 2 do livro texto, exceto 7 e 8 letra b. Lista 1 8 de abril de 2013 1 Exercícios Básicos 1.1 Na bibliografia Algorithms: Capítulo 0, exercícios 1 e 2. Tardos: Todos exercícios do cap 2 do livro texto, exceto 7 e 8 letra b. 1.2 Outros 1. Projete

Leia mais

Algoritmo. Exemplo. Definição. Programação de Computadores Comparando Algoritmos. Alan de Freitas

Algoritmo. Exemplo. Definição. Programação de Computadores Comparando Algoritmos. Alan de Freitas Algoritmos Programação de Computadores Comparando Algoritmos Um algoritmo é um procedimento de passos para cálculos. Este procedimento é composto de instruções que definem uma função Até o momento, vimos

Leia mais

Edital de Seleção 032/2016 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões

Edital de Seleção 032/2016 PROPESP/UFAM. Prova de Conhecimento. Caderno de Questões Edital de Seleção 032/2016 PROPESP/UFAM Prova de Conhecimento Caderno de Questões CANDIDATO: INSCRIÇÃO: Assinatura conforme identidade INSTRUÇÕES PARA O CANDIDATO: Verifique o seu nome e o número da sua

Leia mais

SCC Capítulo 3 Análise de Algoritmos - Parte 2

SCC Capítulo 3 Análise de Algoritmos - Parte 2 SCC-501 - Capítulo 3 Análise de Algoritmos - Parte 2 João Luís Garcia Rosa 1 1 Departamento de Ciências de Computação Instituto de Ciências Matemáticas e de Computação Universidade de São Paulo - São Carlos

Leia mais

Métodos de Ordenação Parte 3

Métodos de Ordenação Parte 3 Estrutura de Dados II Métodos de Ordenação Parte 3 Prof a Márcio Bueno ed2tarde@marciobueno.com / ed2noite@marciobueno.com Material baseado nos materiais do Prof. Robson Lins Classificação em Memória Primária

Leia mais

INF 1010 Estruturas de Dados Avançadas

INF 1010 Estruturas de Dados Avançadas INF 1010 Estruturas de Dados Avançadas Complexidade de Algoritmos 2012 DI, PUC-Rio Estruturas de Dados Avançadas 2012.2 1 Introdução Complexidade computacional Termo criado por Hartmanis e Stearns (1965)

Leia mais

AULA 24. Algoritmos p.856/905

AULA 24. Algoritmos p.856/905 AULA 24 Algoritmos p.856/905 Máximo divisor comum CLRS 31.1 e 31.2 Algoritmos p.857/905 Divisibilidade Suponha que a, b e d são números inteiros. Dizemos que d divide a se a = k d para algum número inteiro

Leia mais

Divisão e conquista. Há divisão quando o algoritmo tem pelo menos 2 chamadas recursivas no corpo

Divisão e conquista. Há divisão quando o algoritmo tem pelo menos 2 chamadas recursivas no corpo Divisão e conquista Divisão: resolver recursivamente problemas mais pequenos (até caso base) Conquista: solução do problema original é formada com as soluções dos subproblemas á divisão quando o algoritmo

Leia mais

Análise e Projeto de Algoritmos

Análise e Projeto de Algoritmos Análise e Projeto de Algoritmos Mestrado em Ciência da Computação Prof. Dr. Aparecido Nilceu Marana Faculdade de Ciências I think the design of efficient algorithms is somehow the core of computer science.

Leia mais

Aprendendo a Programar Programando numa Linguagem Algorítmica Executável (ILA)

Aprendendo a Programar Programando numa Linguagem Algorítmica Executável (ILA) Jaime Evaristo Sérgio Crespo Aprendendo a Programar Programando numa Linguagem Algorítmica Executável (ILA) Segunda Edição Capítulo 7 Versão 13052010 7. Pesquisa e Ordenação 7.1 Introdução Embora os problemas

Leia mais

Algoritmos de Ordenação: QuickSort

Algoritmos de Ordenação: QuickSort Algoritmos de Ordenação: QuickSort ACH2002 - Introdução à Ciência da Computação II Delano M. Beder Escola de Artes, Ciências e Humanidades (EACH) Universidade de São Paulo dbeder@usp.br 10/2008 Material

Leia mais

Projeto e Análise de Algoritmos

Projeto e Análise de Algoritmos Projeto e Análise de Algoritmos A. G. Silva Baseado nos materiais de Souza, Silva, Lee, Rezende, Miyazawa Unicamp Ribeiro FCUP 18 de agosto de 2017 Conteúdo programático Introdução (4 horas/aula) Notação

Leia mais

Análise de algoritmos. Parte I

Análise de algoritmos. Parte I Análise de algoritmos Parte I 1 Procedimento X Algoritmo Procedimento: sequência finita de instruções, que são operações claramente descritas, e que podem ser executadas mecanicamente, em tempo finito.

Leia mais

Estruturas de Dados Algoritmos

Estruturas de Dados Algoritmos Estruturas de Dados Algoritmos Prof. Eduardo Alchieri Algoritmos (definição) Sequência finita de instruções para executar uma tarefa Bem definidas e não ambíguas Executáveis com uma quantidade de esforço

Leia mais

Universidade Federal da Grande Dourados Faculdade de Ciências Exatas e Tecnologia Bacharelado em Sistemas de Informação Estruturas de Dados I Lista II

Universidade Federal da Grande Dourados Faculdade de Ciências Exatas e Tecnologia Bacharelado em Sistemas de Informação Estruturas de Dados I Lista II Universidade Federal da Grande Dourados Faculdade de Ciências Exatas e Tecnologia Bacharelado em Sistemas de Informação Estruturas de Dados I Lista II Professor: MSc. Rodrigo Porfírio da Silva Sacchi 30

Leia mais

Algoritmos de retrocesso

Algoritmos de retrocesso Algoritmos de retrocesso Algoritmos em que se geram escolhas que vão sendo testadas e eventualmente refeitas Problemas para os quais não existem algoritmos eficientes: retrocesso é melhor que pesquisa

Leia mais

Programação Linear M É T O D O S : E S T A T Í S T I C A E M A T E M Á T I C A A P L I C A D A S D e 1 1 d e m a r ç o a 2 9 d e a b r i l d e

Programação Linear M É T O D O S : E S T A T Í S T I C A E M A T E M Á T I C A A P L I C A D A S D e 1 1 d e m a r ç o a 2 9 d e a b r i l d e Programação Linear A otimização é o processo de encontrar a melhor solução (ou solução ótima) para um problema. Existe um conjunto particular de problemas nos quais é decisivo a aplicação de um procedimento

Leia mais

Método Simplex. Marina Andretta ICMC-USP. 19 de outubro de 2016

Método Simplex. Marina Andretta ICMC-USP. 19 de outubro de 2016 Método Simplex Marina Andretta ICMC-USP 19 de outubro de 2016 Baseado no livro Introduction to Linear Optimization, de D. Bertsimas e J. N. Tsitsiklis. Marina Andretta (ICMC-USP) sme0211 - Otimização linear

Leia mais

CES-11. Noções de complexidade de algoritmos. Complexidade de algoritmos. Avaliação do tempo de execução. Razão de crescimento desse tempo.

CES-11. Noções de complexidade de algoritmos. Complexidade de algoritmos. Avaliação do tempo de execução. Razão de crescimento desse tempo. CES-11 Noções de complexidade de algoritmos Complexidade de algoritmos Avaliação do tempo de execução Razão de crescimento desse tempo Notação O Exercícios COMPLEXIDADE DE ALGORITMOS Importância de análise

Leia mais

5. Análise de Complexidade de Algoritmos. João Pascoal Faria (versão original) Ana Paula Rocha (versão 2003/2004) Luís Paulo Reis (versão 2005/2006)

5. Análise de Complexidade de Algoritmos. João Pascoal Faria (versão original) Ana Paula Rocha (versão 2003/2004) Luís Paulo Reis (versão 2005/2006) 5. Análise de Complexidade de Algoritmos João Pascoal Faria (versão original) Ana Paula Rocha (versão 2003/2004) Luís Paulo Reis (versão 2005/2006) FEUP - MIEEC Prog 2-2006/2007 Introdução Algoritmo: conjunto

Leia mais

Solução de Recorrências

Solução de Recorrências CENTRO FEDERAL DE EDUCAÇÃO TECNOLÓGICA DE MINAS GERAIS Solução de Recorrências Algoritmos e Estruturas de Dados I Natália Batista https://sites.google.com/site/nataliacefetmg/ nataliabatista@decom.cefetmg.br

Leia mais

Complexidade de Algoritmos

Complexidade de Algoritmos Complexidade de Algoritmos! Uma característica importante de qualquer algoritmo é seu tempo de execução! é possível determiná-lo através de métodos empíricos, considerando-se entradas diversas! é também

Leia mais

Ordenação Externa. Ordenação Externa. Ordenação Externa. Ordenação Externa

Ordenação Externa. Ordenação Externa. Ordenação Externa. Ordenação Externa Ordenação Externa Ordenação Externa Estrutura de Dados II Prof. Guilherme Tavares de Assis Universidade Federal de Ouro Preto UFOP Instituto de Ciências Exatas e Biológicas ICEB Departamento de Computação

Leia mais

Ordenação: QuickSort. Prof. Túlio Toffolo BCC202 Aula 15 Algoritmos e Estruturas de Dados I

Ordenação: QuickSort. Prof. Túlio Toffolo  BCC202 Aula 15 Algoritmos e Estruturas de Dados I Ordenação: QuickSort Prof. Túlio Toffolo http://www.toffolo.com.br BCC202 Aula 15 Algoritmos e Estruturas de Dados I QuickSort Proposto por Hoare em 1960 e publicado em 1962. É o algoritmo de ordenação

Leia mais

Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula

Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula Universidade Estadual de Mato Grosso do Sul Bacharelado em Ciência da Computação Algoritmos e Estruturas de Dados II Prof. Fabrício Sérgio de Paula Tópicos Introdução Ordenação por bolha (bubble sort)

Leia mais

BCC202 - Estrutura de Dados I

BCC202 - Estrutura de Dados I BCC202 - Estrutura de Dados I Aula 13: Ordenação: MergeSort Reinaldo Fortes Universidade Federal de Ouro Preto, UFOP Departamento de Computação, DECOM Website: www.decom.ufop.br/reifortes Email: reifortes@iceb.ufop.br

Leia mais

Complexidade Assintótica de Programas Letícia Rodrigues Bueno

Complexidade Assintótica de Programas Letícia Rodrigues Bueno Complexidade Assintótica de Programas Letícia Rodrigues Bueno Análise de Algoritmos 1. Introdução; Análise de Algoritmos 1. Introdução; 2. Conceitos básicos; Análise de Algoritmos 1. Introdução; 2. Conceitos

Leia mais

Algoritmos de retrocesso

Algoritmos de retrocesso Algoritmos de retrocesso Algoritmos em que se geram escolhas que vão sendo testadas e eventualmente refeitas Problemas para os quais não existem algoritmos eficientes: retrocesso é melhor que pesquisa

Leia mais

MÉTODOS DE ORDENAÇÃO. Introdução à Programação SI2

MÉTODOS DE ORDENAÇÃO. Introdução à Programação SI2 MÉTODOS DE ORDENAÇÃO Introdução à Programação SI2 2 Conteúdo Conceitos básicos Classificação por troca Classificação por inserção Classificação por seleção 3 Conceitos Básicos Ordenar: processo de rearranjar

Leia mais

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO DEPARTAMENTO DE CIÊNCIAS DA COMPUTAÇÃO. 4 a Lista de Exercícios Gabarito de algumas questões.

UNIVERSIDADE FEDERAL DO RIO DE JANEIRO DEPARTAMENTO DE CIÊNCIAS DA COMPUTAÇÃO. 4 a Lista de Exercícios Gabarito de algumas questões. UNIVERSIDADE FEDERAL DO RIO DE JANEIRO DEPARTAMENTO DE CIÊNCIAS DA COMPUTAÇÃO MATEMÁTICA COMBINATÓRIA 4 a Lista de Exercícios Gabarito de algumas questões. Este gabarito foi feito direto no computador

Leia mais

Prova 1 PMR2300 / PMR3201 1o. semestre 2015 Prof. Thiago Martins

Prova 1 PMR2300 / PMR3201 1o. semestre 2015 Prof. Thiago Martins Prova 1 PMR2300 / PMR3201 1o. semestre 2015 Prof. Thiago Martins Instruções: Escreva o nome e o número USP na folha de papel almaço. Indique na linha seguinte quatro das cinco questões abaixo que devem

Leia mais

Comportamento Assintótico. Algoritmos e Estruturas de Dados Flavio Figueiredo (http://flaviovdf.github.io)

Comportamento Assintótico. Algoritmos e Estruturas de Dados Flavio Figueiredo (http://flaviovdf.github.io) Comportamento Assintótico Algoritmos e Estruturas de Dados 2 2017-1 Flavio Figueiredo (http://flaviovdf.github.io) 1 Até Agora Falamos de complexidade de algoritmos com base no número de passos Vamos generalizar

Leia mais

Técnicas de Desenho de Algoritmos

Técnicas de Desenho de Algoritmos Técnicas de Desenho de Algoritmos Mudança de ênfase: da implementação de algoritmos para o desenho de algoritmos A ver: 5 tipos de algoritmos abordagem ao problema exemplos complexidade em tempo e espaço

Leia mais