Você está na página 1de 21

Aula 10 – Algoritmos Gulosos

25089/1001525 – Projeto e Análise de Algoritmos


2019/2 - Turma A
Prof. Dr. Murilo Naldi

naldi@dc.ufscar.br
Agradecimentos


Aos professores Mário Felice e Diego Furtado por ceder
parte do material utilizado.

Material inspirado nas aulas do prof. Tim Roughgarden
O que são?


Algoritmo que iterativamente fazem decisões
míopes
– Geralmente é fácil projetar
– Razoavelmente fácil analisar o tempo de
execução

Mas não é fácil projetar um algoritmo guloso
correto
– Muito menos provar sua corretude
Tipo de prova de corretude


Por indução no número de iterações
– Mostrando que a escolha gulosa sempre está
correta

Por um argumento de troca entre soluções
– Que pode ser por contradição para mostrar
que algo diferente da solução gulosa é pior
– Ou iterativamente, transformando uma
solução qualquer em gulosa sem piorar seu
custo
Problema de Escalonamento


Temos uma única unidade de processamento
– E diversas tarefas para realizar
● Cada um com um peso (prioridade) w j >0 e uma
duração lj > 0

Uma solução é uma ordem (permutação) de tarefas
– O objetivo é uma solução que minimize a soma
ponderada dos tempos de término, ou seja:
ntarefas

∑ wjcj
j=1
– Onde cj é o tempo em que j-ésima tarefa é concluída
Problema de Escalonamento

● Note que cj é igual ao tempo de execução li de toda


tarefa i que vem antes de j mais o próprio lj

Exemplo:
– Considere três tarefas com durações
● l1= 1, l2 = 2 e l3 =3
– Quais os tempos de término dos escalonamentos?

a)R: 3,5,6 b)R: 1,3,6


Problema do Escalonamento

● Supondo que os pesos das tarefas são w 1 = 3, w2 = 2, w3


= 1, qual o valor da função objetivo dos dois casos?

a) 1*3 + 2*5 + 3*6 = 31 b) 3*1 + 2*3+ 1*6 = 15



Como podemos fazer um algoritmo que minimize a
soma ponderada dos tempos de término, isso é:
ntarefas

∑ wjcj
j=1
Algortimo Guloso para Escalonamento


Que tal usar uma abordagem que utiliza generalizações a
partir de casos particulares?
– Caso a) → toda tarefa tem o mesmo peso
– Caso b) → toda tarefa tem a mesma duração

Qual seria um bom critério guloso para cada caso?
Algortimo Guloso para Escalonamento


Que tal usar uma abordagem que utiliza generalizações a
partir de casos particulares?
– Caso a) → toda tarefa tem o mesmo peso
– Caso b) → toda tarefa tem a mesma duração

Qual seria um bom critério guloso para cada caso?
– Caso a) → itens mais curtos antes (pois a duração de
uma tarefa impacta o tempo de término que vem
depois dela)
– Caso b) → itens mais pesados antes (pois o peso
multiplica o tempo de término)
Exemplos

● Duas tarefas l1 = 1 e l2 = 2 ● Duas tarefas l1 = l2 = 1 e


w1 = w 2 = 1 w1 = 1 , w2 = 2


1*1 + 1*3 = 4 ●
1*1 + 2*2 = 5


1*2 + 1*3 = 5 ●
2*1 + 1*2 = 4
Generalizando e resolvendo conflitos


Quando a tarefa é mais curta e mais pesada que
outra, ela certamente deve vir antes

Mas o que fazer quando uma tarefa i é mais curta e
outra j é mais pesada, ou seja, li <lj e wi < wj?
– Uma possibilidade é combinar os valores de
duração e peso em uma única pontuação que:

Aumenta como peso

Diminui com a duração
– E escalonar as tarefas em ordem decrescente de
pontuação
Generalizando e resolvendo conflitos


Quais funções atendem esses critérios:
– Duas possibilidades entre várias:
f1(i) = wi – li f2(i) = wi / li
– No máximo um destes critérios está correto!

Talvez, nenhum deles!

Vamos procurar cenários em que eles tenham
comportamento distinto entre si (e do esperado)
para colocá-los a prova!
– São os chamados contra-exemplos.
Exemplo de cenário


Duas tarefas:
– li = 1 w i = 3
– lj = 2, wj = 5
● f1(i) = 3 - 1 = 2 ● f2(i) = 3 / 1 = 3
● f1(j) = 5 - 2 = 3 ● f2(j) = 5 / 2 = 2,5

5* 2 + 3*3 = 19 ●
3*1 + 5*3 =18
Generalizando e resolvendo conflitos

● Portanto, a função f2(i) = wi/li seria nossa escolhida.


Mas será que ela é correta, ou seja, um algoritmo
guloso que escalona as tarefas em ordem
decrescente seguindo essa função sempre devolve
o escalonamento ótimo (de custo mínimo)?
– Isso não é tão óbvio, mas sim

Iremos demostrar mais adiante

Antes disso, vamos analisar a eficiência do pior caso
do algoritmo.
Eficiência pior caso

● Um laço para calcular f2 para todos as tarefas


– O(n)

Ordena as tarefas por ordem decrescente de
pontuação
– O(n log n)

O vetor ordenado é a solução, portanto a
complexidade de tempo é
– O(n log n)

Em questão de memória, um vetor auxiliar pode ser
usado para armazenar os valores de f2 (ou não)?
Eficiência pior caso
● Um laço para calcular f2 para todos as tarefas
– O(n)

Ordena as tarefas por ordem decrescente de
pontuação
– O(n log n)

O vetor ordenado é a solução, portanto a
complexidade de tempo é
– O(n log n)

Em questão de memória, um vetor auxiliar pode ser
usado para armazenar os valores de f2 (ou não)?
– Sim, basta fazer o cálculo de f2 dentro da
ordenação
Prova de Corretude


Vamos fazer a prova usando argumento de troca
– Técnica por contradição

Para simplificar, vamos supor que não ocorrem
empates, ou seja, i,j temos f(i) ≠ f (j)

Seja σ o escalonamento produzido por nosso
algoritmo

Por contradição, suponha que σ* é um
escalonamento ótimo e que ele é diferente de σ
Prova de Corretude


Para simplificar a notação, vamos renomear as
tarefas de acordo com a ordem em σ, ou seja:

w1 w 2 w3 wn
> > >…>
l1 l2 l3 ln

Como σ* é diferente de σ, deve haver alguma
inversão em algum par de tarefas adjacentes i e j tal
que:
– i está antes de j em σ*
– i > j → wj/lj > wi/li → wjli> wilj
Prova de Corretude


Vamos verificar o que acontece com o custo de σ* se
invertemos i com j
1)Nada muda para os itens antes de i e j, pois as
durações destes não afetam os tempos de término
dos primeiros
2) Nada muda para os itens depois de i e j, pois ambas
as durações destes contribuem para os tempos de
término de todos que vem depois, independente da
ordem de i e j
ntarefas min(i , j)−1 ntarefas

∑ wk ck = ∑ w k ' ck ' + ∑ w k ' ' c k ' ' + wi ci +w j c j


k=1 k ' =1 k ' ' =max (i , j)+1
Prova de Corretude


Agora vamos focar nas contribuições de i e j para a
função objetivo
– Note que a troca faz:
● O tempo de término da tarefa i aumentar de lj
–Pois j passa ser processado antes de i
● O tempo de término da tarefa j diminui de li
Pois i passa a ser processado depois de j

– Portanto, a variação da função objetivo após a
troca é:
● wilj - wjli
Prova de Corretude

● Como, pelo critério guloso, temos que wjli > wilj


– Temos wilj - wjli < 0, ou seja, o custo de função
objetivo diminui com a troca, contradizendo o fato
de que σ* era uma solução ótima

Com isso concluímos a prova que nosso algoritmo
guloso é ótimo

No caso de considerarmos empates, o argumento é
o mesmo, mas utilizamos indução para mostrar que
realizando sucessivas trocas transformamos uma
solução qualquer (inclusive a ótima) na solução
gulosa sem nunca piorar o custo da solução

Você também pode gostar