Análise e Síntese de Algoritmos Algoritmos Greedy CLRS, Cap. 16 Resumo • Algoritmos Greedy: – Um primeiro exemplo • Problema de Selecção de Actividades – Características das abordagens greedy – Exemplo: Problema da Mochila – Exemplo: Minimizar Tempo no Sistema – Um exemplo final: Códigos de Huffman 2003/2004 Análise e Síntese de Algoritmos 2 Técnicas para Síntese de Algoritmos • Dividir para conquistar • Programação dinâmica • Algoritmos greedy – Estratégia: a cada passo da execução do algoritmo escolher opção que localmente se afigura como a melhor para encontrar solução óptima • Estratégia permite obter solução óptima? – Exemplos: • Kruskal, Prim, Dijkstra, etc. 2003/2004 Análise e Síntese de Algoritmos 3 Exemplo: Selecção de Actividades • Seja S = { 1, 2, …, n } um conjunto de actividades que pretendem utilizar um dado recurso – Apenas uma actividade pode utilizar recurso de cada vez – Actividade i: • tempo de início: si • tempo de fim: ti • execução da actividade durante [si, ti) – Actividades i e j compatíveis apenas se [si, ti) e [sj, tj) não se intersectam • Objectivo: encontrar conjunto máximo de actividades mutuamente compatíveis 2003/2004 Análise e Síntese de Algoritmos 4 Exemplo (Cont.) • Admitir que f1 f2 … fn • Escolha greedy: – Escolher actividade com o menor tempo de fim • Porquê? – Maximizar espaço para restantes actividades serem realizadas 2003/2004 function Selecionar_Actividades_Greedy(s,f) n = length[s] A={1} j=1 for i = 2 to n if si fj then A=A{i} j=i return A Análise e Síntese de Algoritmos 5 Exemplo (Cont.) • Algoritmo encontra soluções de tamanho máximo para o problema de selecção de actividades – Existe uma solução óptima que começa com escolha greedy, i.e. actividade 1 • A: solução óptima que começa em k • B=A-{k}{1} • f1 fk – Actividades em B são mutuamente disjuntas e A = B – B é também solução óptima ! 2003/2004 Análise e Síntese de Algoritmos 6 Exemplo (cont.) – Após escolha greedy, problema reduz-se a encontrar solução para actividades compatíveis com actividade 1 • Seja A solução óptima, e que começa em 1 • A’ = A - { 1 } é solução óptima para S’ = { i S : si f1 } – Caso contrário, existiria uma solução B’ > A’ para S’ que permitiria obter solução B para S com mais actvidades do que A; uma contradição ! – Aplicar indução no número de escolhas greedy • Algoritmo calcula solução óptima ! • Exemplo 2003/2004 Análise e Síntese de Algoritmos 7 Características das Abordagens Greedy • Propriedade da escolha greedy – Óptimo (global) para o problema pode ser encontrado realizando escolhas locais óptimas • Sub-estrutura óptima – Solução óptima do problema engloba soluções óptimas para sub-problemas 2003/2004 Análise e Síntese de Algoritmos 8 Outro Exemplo: Problema da Mochila • Definição do problema: – – – – – Dados n objectos (1, …, n) e uma mochila Cada objecto tem um valor vi e um peso wi É possível transportar fracção xi do objecto: 0 xi 1 Peso transportado pela mochila não pode exceder W Objectivo: • maximizar o valor transportado pela mochila e respeitar a restrição de peso • Formalização: n max xivi i 1 n s.t. xiw i W i 1 v i 0, w i 0, 0 x i 1, 1 i n 2003/2004 Análise e Síntese de Algoritmos 9 Exemplo (Cont.) • Observações: – Soma do peso dos n objectos deve exceder peso limite W – Solução óptima tem que encher mochila completamente, xi w i W • Caso contrário poderiamos transportar mais fracções, com mais valor ! • Algoritmo: Tempo de execução: O(n), ou O(n lg n) 2003/2004 function Encher_Mochila_Greedy(v,w,W) while weight < W escolher elemento i com vi/wi máximo if wi + weight W then xi = 1; weight += wi else xi = (W-weight)/ wi; weight = W Análise e Síntese de Algoritmos 10 Exemplo (Cont.) • Se objectos forem escolhidos por ordem decrescente de vi/wi, então algoritmo encontra solução óptima – – – – Admitir: v1/w1 … vn/wn X = (x1, …, xn): solução calculada por algoritmo greedy Se xi = 1 para todo o i, solução é necessariamente óptima Caso contrário, seja j menor indíce tal que xj < 1 • Nota: – – – – 2003/2004 xi = 1, i < j xi = 0, i > j Relação de pesos: Valor da solução é: ni1 x i w i W i1 x i v i VX n Análise e Síntese de Algoritmos 11 Exemplo (Cont.) – Y = (y1, …, yn): uma qualquer solução possível n • Peso: i1 y i w i W n • Valor: V Y y i v i i 1 – Relação X vs. Y: i1x i y i w i 0 n – Notar que, VX VY i1x i y i v i i1x i y i w i n n vi wi – Seja j menor indíce tal que xj < 1. Casos possíveis: • i < j, xi = 1, xi - yi 0, enquanto vi/wi vj/wj Verifica-se • i > j, xi = 0, xi - yi 0, enquanto vi/wi vj/wj sempre: • i = j, vi/wi = vj/wj xi yi v i w i xi yi v j w j 2003/2004 Análise e Síntese de Algoritmos 12 Exemplo (Cont.) – Verifica-se, V X V Y i1 x i y i w i v i w i v j w j i1 x i y i w i 0 n n – V(X) é a melhor solução possível entre todas as soluções possíveis • Algoritmo calcula solução óptima ! 2003/2004 Análise e Síntese de Algoritmos 13 Exemplo: Minimizar Tempo no Sistema • Dado um servidor com n clientes, com tempo de serviço conhecido (i.e. cliente i leva tempo ti), objectivo é minimizar tempo total dispendido no sistema (pelo total dos n clientes) min imizar T i1 tempo total dispendido no sistema pelo cliente i n • Exemplo • Solução (greedy): – Servir clientes por ordem crescente do tempo de serviço 2003/2004 Análise e Síntese de Algoritmos 14 Exemplo (Cont.) • Algoritmo greedy encontra solução óptima – P = p1p2…pn, permutação dos inteiros de 1 a n • Seja si t pi – E.g. s1 t p1 t 5 – Com clientes servidos pela ordem P, tempo de serviço do cliente a ser servido na posição i é si – Tempo total passado no sistema por todos os clientes é: s1 aparece n vezes, n TP k 1 n k 1sk e sn aparece 1 vez – Assumir clientes não ordenados por ordem crescente de tempo de serviço em P • Então existem a e b, com a < b, e sa > sb 2003/2004 Análise e Síntese de Algoritmos 15 Exemplo (cont.) – Trocar ordem dos clientes a e b, de modo a obter ordem P’ • Corresponde a P com inteiros pa e pb trocados TP' (n a 1)sb n b 1s a n n k 1sk k 1 k a,b – Obtendo-se, TP TP' n a 1sa sb n b 1sb sa b a sa sb 0 – P’ é uma ordem melhor (com menor tempo de serviço) • Algoritmo calcula solução óptima ! 2003/2004 Análise e Síntese de Algoritmos 16 Exemplo: Códigos de Huffman • Aplicação: compressão de dados • Exemplo: – Ficheiro com 100000 caracteres Frequência Código Fixo a 45 000 b 13 001 c 12 010 d 16 011 e f 9 100 5 101 – Tamanho do ficheiro comprimido: 3x100000 = 300000 bits – Código de largura variável pode ser melhor do que código com largura fixa • Aos caracteres mais frequentes associar códigos de menor dimensão 2003/2004 Análise e Síntese de Algoritmos 17 Exemplo (Cont.) • Código de comprimento variável: Frequência Código Variável a 45 0 b 13 101 c 12 100 d 16 111 e f 9 1101 5 1100 – Número de bits necessário: • (45*1 + 13*3 + 12*3 + 16*3 + 9*4 + 5*4)*1000 = 224000 bits • Códigos livres de prefixo: – Nenhum código é prefixo de outro código – 001011101 0.0.101.1101 – Código óptimo representado por árvore binária (completa) 2003/2004 Análise e Síntese de Algoritmos 18 Códigos Livres de Prefixo 100 0 Árvore binária completa: cada nó interno com 2 filhos 1 a:45 55 25 0 c:12 2003/2004 Código óptimo representado por árvore completa 1 0 30 1 0 b:13 1 14 d:16 0 1 f:5 e:9 Análise e Síntese de Algoritmos 19 Exemplo (Cont.) • Dada uma árvore T associada a um código livre de prefixo – f(c): – dT(c): frequência (ocorrências) do caracter c no ficheiro profundidade da folha c na árvore BT f c dT c cC Número de bits necessário para representar ficheiro • Código de Huffman: construir árvore T que corresponde ao código livre de prefixo óptimo – Começar com |C| folhas (para cada um dos caracteres do ficheiro) e realizar |C| - 1 operações de junção para obter árvore final 2003/2004 Análise e Síntese de Algoritmos 20 Exemplo (Cont.) function Huffman(C) n = |C| Q=C // Constrói fila de prioridade for i = 1 to n - 1 z = AllocateNode() x = left[z] = ExtractMin(Q) y = right[z] = ExtractMin(Q) f[z] = f[x] + f[y] Insert(Q, z) return ExtractMin(Q) Tempo de execução: O(n lg n) 2003/2004 Análise e Síntese de Algoritmos 21 Exemplo (Cont.) • Exemplo • Código de Huffman para alfabeto C: – Cada caracter cC com frequência f[c] – x, y caracteres em C com as menores frequências – Código óptimo para C representado por árvore binária T 2003/2004 Análise e Síntese de Algoritmos 22 Exemplo (Cont.) • Facto 1: (propriedade da escolha greedy) – Existe código livre de prefixo para C tal que os códigos para x e y (com as menores frequências) têm o mesmo comprimento e diferem apenas no último bit • T árvore que representa código óptimo • b e c caracteres são nós folha de maior profundidade em T • Admitir, f[b] f[c], e f[x] f[y] • Notar também que, f[x] f[b], e f[y] f[c] • T’: trocar posições de b e x em T • T’’: trocar posições de c e y em T’ • B(T) B(T’) B(T’) B(T’’) (*) • Mas, T é óptimo B(T’), B(T’’) B(T) • T’’ é uma árvore óptima ! 2003/2004 Análise e Síntese de Algoritmos 23 Exemplo (Cont.) • (*) BT BT' f c dT c f c dT' c cC cC f [ x]dT x f [b]dT b f [ x]dT ' x f [b]dT ' b f [ x]dT x f [b]dT b f [ x]dT b f [b]dT x f [b] f [ x]dT b dT x 0 2003/2004 Análise e Síntese de Algoritmos 24 Exemplo (Cont.) • Facto 2: (subestrutura óptima) – Sendo z um nó interno de T, e x e y nós folha – Considerar um caracter z com f[z] = f[x] + f[y] – Então T’ = T - {x, y} é óptima para C’ = C - {x, y} { z } • B(T) = B(T’) + f[x] + f[y] (**) • Se T’ é não óptimo, então existe T’’ tal que B[T’’] < B[T’] • Mas z é nó folha também em T’’ (devido a facto 1) – Adicionando x e y como filhos de z em T’’ – Código livre de prefixo para C com custo: » B[T’’] + f[x] + f[y] < B[T] – mas T é óptimo (B[T’’] + f[x] + f[y] B[T]); pelo queT’ também é óptimo 2003/2004 Análise e Síntese de Algoritmos 25 Exemplo (Cont.) • (**) f [ x ]dT x f [ y ]dT y 2003/2004 f [ x] f [ y]dT ' z 1 f [ z]dT ' z f [ x ] f [ y ] Análise e Síntese de Algoritmos 26 Exemplo (Cont.) • O algoritmo Huffman produz um código livre de prefixo óptimo – Ver factos anteriores • Propriedade da escolha greedy • Sub-estrutura óptima 2003/2004 Análise e Síntese de Algoritmos 27 Revisão • Algoritmos greedy – Características das abordagens greedy – Exemplos de aplicação • String Matching 2003/2004 (CLRS, Cap. 32) Análise e Síntese de Algoritmos 28