Algoritmos gulosos
Provas por troca para atividades, mochila fracionária, ordem de serviço e códigos de Huffman.
Com atividades , e , escolher a que começa mais cedo seleciona apenas . Escolher a que termina mais cedo seleciona e depois , com duas atividades em vez de uma. O exemplo mostra que a regra de escolha decide o resultado. Um algoritmo guloso fixa uma escolha sem a desfazer e resolve o que resta com a mesma regra.
Para justificar a regra, é preciso provar que existe uma solução ótima compatível com essa escolha e que o problema restante conserva a mesma estrutura. Uma instância onde a regra funciona não prova a regra. Uma instância onde falha refuta-a.
Seleção de atividades
Cada atividade tem início e fim , com . Uma pessoa faz atividades sem sobreposição e quer maximizar a quantidade. Usamos intervalos , pelo que uma atividade pode começar no instante em que a anterior termina.
A regra é ordenar por fim crescente e aceitar a primeira atividade compatível com a última escolhida. O fim mais cedo deixa pelo menos tanto tempo livre como qualquer alternativa para continuar, o que torna plausível que a escolha não prejudique o resto. A prova abaixo confirma essa intuição.
Para , , , e , a ordem por fim é . Escolhemos , rejeitamos por ser incompatível, escolhemos , rejeitamos e escolhemos . O resultado tem três atividades.
Prova por troca
Seja a atividade de fim mais cedo e uma solução ótima. Ordena as atividades de por tempo e chama à primeira. Como , substituir por mantém a compatibilidade com todas as atividades seguintes. A quantidade não muda. Existe, portanto, uma solução ótima que começa por .
Depois de escolher , o resto é o mesmo problema restrito às atividades que começam a partir de . Se o resto escolhido não fosse ótimo, podíamos substituí-lo por um melhor e melhorar a solução completa. As escolhas são ótimas por indução sobre o número de atividades.
A ordenação custa e a passagem custa . Se a entrada já estiver ordenada por fim, o custo é . Empates no fim podem ser resolvidos por qualquer ordem válida, sem alterar a garantia.
Escolher o início mais cedo falha com , e : escolhe uma atividade em vez de duas. Escolher a duração mais curta também não tem esta prova. Se cada atividade tiver um valor diferente e o objetivo for somar valores, maximizar a quantidade é outro problema e pode exigir programação dinâmica.
Carga em ordem e blocos contíguos
Uma sequência de caixas com pesos tem de ser carregada nessa ordem em camiões de capacidade 10. Só um camião recebe caixas de cada vez. Enchemos o primeiro com e o segundo com : dois camiões. Mandar o primeiro embora depois do 6 deixaria três blocos , e , com um camião a mais.
Assume para cada caixa, capacidade igual em todos os camiões, sem reordenar nem repartir caixas. A regra coloca no camião atual o maior prefixo do que falta cuja soma cabe. Quando a próxima caixa já não cabe, abre outro camião. Uma passagem custa e guarda apenas a carga atual e o número de camiões, além das fronteiras se forem pedidas.
A prova acompanha a fronteira de cada bloco. Seja a última caixa carregada pelos primeiros camiões gulosos e a última de qualquer outra solução válida. O primeiro bloco guloso é o maior prefixo que cabe, logo . Supondo , há dois casos. Se , o guloso já passou essa fronteira. Caso contrário, as caixas de até são um sufixo do bloco da outra solução. Como os pesos são positivos, esse sufixo também cabe num camião. O guloso coloca pelo menos essas caixas e fica .
Assim, se uma solução acaba em camiões, e o guloso também já acabou até ao camião . A regra minimiza o número de camiões. A hipótese da ordem é essencial: se pudermos reordenar , dois camiões com chegam, enquanto a regra sobre essa ordem usa três.
Mochila fracionária
Aqui cada objeto é divisível. Com peso , valor e fração , queremos maximizar sujeito a . A densidade é o valor por unidade de peso.
Ordena por densidade decrescente. Leva cada objeto inteiro enquanto couber. Quando um não cabe, leva a fração que preenche a capacidade restante.
Com , , e capacidade 10, levamos inteiro e de . O peso é e o valor é .
A prova troca peso, não objetos inteiros. Se uma solução leva peso de um objeto menos denso enquanto ainda pode levar mais do mais denso, troca uma quantidade do primeiro para o segundo. A capacidade mantém-se e o valor não diminui. Repetindo, existe uma solução ótima que enche primeiro os objetos mais densos. A ordenação dá tempo.
Na mochila 0-1, a troca fracionária é proibida. No mesmo exemplo, o guloso leva e fica com valor 12, enquanto levar e dá 18. A hipótese de divisibilidade era necessária.
Poucas exceções numa mochila 0-1
Na mochila 0-1, assume pesos positivos e valores não negativos. Se apenas objetos têm peso excecional e os restantes partilham o mesmo peso , enumera os subconjuntos excecionais. Rejeita os que excedem e completa cada um com os regulares de maior valor que cabem.
Ordena os regulares por valor decrescente uma vez e guarda somas de prefixos. Para capacidade restante , cabem objetos. A soma dos primeiros valores dá em a melhor conclusão desse ramo: trocar um escolhido por outro de maior valor conserva o peso e não piora o resultado. Com leitura da entrada e até operações por subconjunto, o custo é . Para fixo, o fator exponencial é constante.
Se os regulares tiverem valor igual, mas pesos diferentes, a escolha muda: ordena-os por peso crescente e leva o maior prefixo que cabe. Qualquer seleção de objetos pesa pelo menos tanto como os mais leves. Encontrar o maior prefixo pelas somas acumuladas custa por ramo, por pesquisa binária. O total é .
Quando peso e valor dos regulares são ambos iguais, já não há ordenação: calcula diretamente quantos cabem. A pesquisa pode custar depois de ler e confirmar os objetos. O custo total inclui . Uma tabela em não é necessária nestes casos. Se outra parte regular exigisse DP em capacidade binária, o resultado poderia ser apenas pseudopolinomial.
Trocos e condições do sistema
Escolher a maior moeda que cabe pode falhar mesmo com stock ilimitado e moeda de valor 1. Com denominações 1, 3 e 4 e alvo 6, escolhe , três moedas. O ótimo é , duas.
Um sistema é canónico se esse guloso devolve o mínimo de moedas para todo o alvo com stock ilimitado. Não basta as denominações estarem ordenadas. Mesmo um sistema canónico ilimitado pode precisar de outra estratégia quando há stocks finitos. Um algoritmo deve distinguir “não consegui completar com esta regra” de “não existe solução”.
Ordem de serviço
Há clientes disponíveis desde o início, um servidor e tempos positivos . Sem interrupções, queremos minimizar a soma dos tempos de conclusão. É equivalente a minimizar a espera total, porque a soma dos tempos de serviço é fixa.
A regra é servir por duração crescente. Para durações 4, 1 e 3, a ordem inicial tem conclusões 4, 5 e 8, soma 17. A ordem 1, 3, 4 tem conclusões 1, 4 e 8, soma 13.
Para provar, considera dois clientes adjacentes e , depois de um prefixo de duração . Na ordem , a contribuição é . Na ordem , é . A primeira menos a segunda é . Se , trocar reduz o total e não muda os clientes posteriores. Eliminar inversões produz a ordem crescente.
A duração total até terminar todos é sempre , pelo que não é esse total que a regra minimiza. Com tempos de chegada, prioridades ou pesos de espera, o modelo e a prova mudam.
Huffman e códigos sem prefixos
Um código binário é sem prefixos se o código de nenhum símbolo é prefixo do código de outro. Podemos representá-lo por uma árvore binária com símbolos nas folhas. A profundidade de uma folha é o comprimento do seu código.
Para frequências , queremos minimizar , o número total de bits. Huffman retira repetidamente da heap os dois nós de menor frequência, cria um pai com a soma das frequências e volta a inseri-lo.
Com frequências , , , , junta 5 e 7 em 12. Junta 10 e 12 em 22. Junta 15 e 22 em 37.
Um código é , , , . O custo é bits. Somar os pesos dos nós criados também dá , pois cada fusão acrescenta um bit aos símbolos abaixo dela.
Por que juntar os dois mínimos
Numa árvore ótima, escolhe duas folhas irmãs de profundidade máxima. Trocar símbolos para colocar ali os dois menos frequentes não aumenta o custo: se uma frequência menor passa para uma profundidade maior enquanto a maior sobe, a variação é não positiva. Existe, assim, uma árvore ótima em que os dois mínimos são irmãos.
Contrai os dois numa folha de frequência . O custo da árvore original é o custo da contraída mais . Se a árvore contraída não fosse ótima, substituí-la por uma melhor melhoraria a original. A fusão é uma escolha segura e reduz o problema.
A heap dá tempo e espaço. Empates podem produzir códigos diferentes com o mesmo custo. Com um único símbolo, a árvore teria profundidade zero. Um formato de ficheiro real deve definir como representar repetições desse símbolo, por exemplo com um código de um bit e comprimento explícito. A árvore sozinha não define todo o formato de compressão.
Exercícios
Escolher e justificar atividades
As atividades são A=[0,4), B=[1,3), C=[3,5), D=[4,8), E=[5,7) e F=[7,9). Escolhe o maior número de atividades com a regra do fim mais cedo e justifica a primeira escolha por troca.
Pista
Ordena pelos fins e aceita inícios iguais ao fim anterior.
Mais uma pista
A primeira escolha é B. Depois C, E e F são consecutivamente compatíveis.
Solução
A ordem de fins é B,A,C,E,D,F. Escolhemos B,C,E,F, quatro atividades. Se uma solução ótima começa por outra atividade Q, substituir Q por B não prejudica as seguintes, pois B termina até ao fim de Q, ou seja conserva a quantidade e cria uma solução ótima compatível com B. Repetimos o argumento no conjunto de atividades que começam a partir de 3.
Confere a tua resposta:
- Escolhi B,C,E,F.
- Ordenei por fim, não início.
- Justifiquei a troca e o subproblema restante.
Erros frequentes
Escolher A por começar primeiro perde oportunidades. Usar início estritamente maior que o fim rejeita atividades compatíveis sob os intervalos semiabertos do enunciado.
Valor com objetos divisíveis
Uma mochila tem capacidade 8. Há um objeto de peso 4 e valor 12 e outro de peso 6 e valor 12, ambos divisíveis. Qual é o valor máximo?
Pista
As densidades são 3 e 2 unidades de valor por unidade de peso.
Mais uma pista
Depois do primeiro objeto, sobram 4 de capacidade, que levam 4/6 do segundo.
Solução
Leva o primeiro inteiro, valor 12, e dois terços do segundo, valor 8. O total é 20 e o peso é 8. Uma troca de peso do segundo para o primeiro nunca diminui valor enquanto o primeiro não estiver completo, o que justifica preencher nessa ordem.
Erros frequentes
Comparar só valores empata objetos com densidades diferentes. Na versão 0-1 não poderíamos levar dois terços e este valor seria inválido.
Mochila com pesos excecionais
Uma mochila 0-1 tem capacidade 8. Os regulares são R1=(2,6), R2=(2,5) e R3=(2,2); os excecionais são E=(5,11) e F=(3,4). Cada par é peso e valor. Compara os quatro subconjuntos excecionais, completa cada um de forma ótima e encontra a melhor seleção. Generaliza para n-k objetos de igual peso positivo e k exceções, com valores não negativos e k constante.
Solução
Ordenamos os regulares por valor: R1,R2,R3.
| Excecionais | Capacidade restante | Regulares | Valor total |
|---|---|---|---|
| Nenhum | 8 | R1,R2,R3 | 13 |
| E | 3 | R1 | 17 |
| F | 5 | R1,R2 | 15 |
| E,F | 0 | Nenhum | 15 |
Vence E+R1, peso 7 e valor 17. Entre objetos de igual peso, trocar um escolhido por outro de maior valor conserva a capacidade e melhora o resultado.
Ordenamos os regulares uma vez e guardamos somas de prefixos. Para cada seleção excecional viável, cabem regulares. Consultamos o valor dos primeiros q. Contando até k objetos por subconjunto, o custo é , além da reconstrução. Para k fixo, é polinomial, sem tabela em W.
Confere a tua resposta:
- Comparei as quatro seleções excecionais.
- Completei pelos maiores valores regulares.
- Obtive E e R1, valor 17, e derivei o custo.
Encher o bloco ou fechar mais cedo
Camiões de capacidade 10 recebem as caixas de pesos [6,6,4,4] na ordem dada. Cada camião recebe um bloco contíguo; nenhuma caixa pode ser repartida. Executa a regra de encher até a próxima caixa não caber. Fechar um camião mais cedo pode reduzir a quantidade necessária? Justifica para qualquer sequência de pesos positivos que caibam individualmente. Depois admite reordenação: qual é o mínimo nesta instância e que hipótese da prova desapareceu?
Pista
Solução
A regra produz [6], [6,4] e [4], três camiões. Para ordem fixa, seja a fronteira gulosa e a de uma solução válida. O maior prefixo admissível dá . Se e ainda não chegou a , o segmento desde até é um sufixo do bloco da outra solução. Esse sufixo tem peso no máximo 10. O guloso inclui pelo menos esse segmento, ficando . Por indução, nenhuma solução acaba antes do guloso.
Com reordenação, [6,4] e [6,4] dão dois camiões. O peso total 20 exige pelo menos dois, logo são ótimos. Os blocos deixam de ser segmentos da mesma sequência; comparar as suas fronteiras pelo índice original já não justifica o descarte.
Confere a tua resposta:
- Obtive os blocos [6], [6,4] e [4] na ordem dada.
- Provei o avanço das fronteiras para ordem fixa.
- Dei dois blocos de peso 10 quando a reordenação é permitida.