7.1 Otimização de algoritmos dinâmicos.
A otimização de algoritmos dinâmicos foca na melhoria da eficiência de tempo e espaço. Existem várias abordagens de otimização, incluindo o uso de memoização, redução de memória utilizada e otimização da recursão.
1. Memoização:
Memoização é uma técnica onde os resultados dos cálculos são salvos para evitar cálculos repetidos da mesma sub-tarefa.
Exemplo:
No problema da troca de moedas, se você usar uma abordagem recursiva, pode salvar os resultados para as somas já calculadas para evitar cálculos repetidos.
def fibonacci(n, memo={}):
if n in memo:
return memo[n]
if n <= 2:
return 1
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
return memo[n]
2. Solução Tabelada (Bottom-Up):
A solução tabelada (bottom-up) constrói uma tabela de soluções para todas as possíveis sub-tarefas do caso base até o objetivo final. Isso evita os custos de chamadas recursivas.
Exemplo:
No problema da mochila, construindo uma tabela das quantidades mínimas de moedas para cada soma de 0 a S.
def fibonacci(n):
dp = [0] * (n + 1)
dp[1] = dp[2] = 1
for i in range(3, n + 1):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n]
3. Redução do uso de memória:
Em alguns problemas, é possível otimizar o uso de memória, reduzindo o tamanho da tabela ou do array usado para armazenar resultados intermediários.
Exemplo:
No problema da mochila, pode-se usar um array unidimensional em vez de uma tabela bidimensional, se armazenar apenas as linhas correntes e anteriores.
def knapsack_optimized(weights, values, W):
n = len(weights)
dp = [0] * (W + 1)
for i in range(n):
for w in range(W, weights[i] - 1, -1):
dp[w] = max(dp[w], dp[w - weights[i]] + values[i])
return dp[W]
4. Recursão de cauda:
Recursão de cauda é uma chamada recursiva que ocorre no final da função. Isso permite que o compilador ou interpretador otimiza a pilha de chamadas.
Exemplo:
No problema de calcular os números de Fibonacci, pode-se usar recursão de cauda com um acumulador de resultado.
7.2 Aplicação de programação dinâmica em problemas reais.
A programação dinâmica é amplamente utilizada em várias áreas, incluindo ciência da computação, economia, bioinformática e pesquisa operacional. Aqui estão alguns exemplos de seu uso em problemas reais:
1. Otimização de rotas e logística:
Em problemas de logística e sistemas de transporte, a programação dinâmica é usada para encontrar rotas ótimas e minimizar custos.
Exemplo:
Problema do Caixeiro Viajante (Travelling Salesman Problem, TSP) — encontrar o caminho mais curto passando por todas as cidades.
def tsp(graph, start):
n = len(graph)
dp = [[None] * (1 << n) for _ in range(n)]
def visit(city, visited):
if visited == (1 << n) - 1:
return graph[city][start]
if dp[city][visited] is not None:
return dp[city][visited]
result = float('inf')
for next_city in range(n):
if visited & (1 << next_city) == 0:
result = min(result, graph[city][next_city] + visit(next_city, visited | (1 << next_city)))
dp[city][visited] = result
return result
return visit(start, 1 << start)
2. Alinhamento de sequências em bioinformática:
Na bioinformática, a programação dinâmica é usada para alinhar sequências de DNA, RNA e proteínas.
Exemplo:
Algoritmo de Needleman-Wunsch para alinhamento global de sequências e algoritmo de Smith-Waterman para alinhamento local.
def lcs(X, Y):
m, n = len(X), len(Y)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if X[i - 1] == Y[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
3. Cálculos financeiros e planejamento econômico:
A programação dinâmica é aplicada para otimizar portfólios de investimentos, gerenciamento de riscos e planejamento de produção.
Exemplo:
O problema da troca de moedas e o problema da mochila são usados para gerenciar ativos e alocar recursos de forma otimizada.
4. Gestão de estoques e produção:
Na produção e gestão de estoques, a programação dinâmica ajuda a otimizar processos e minimizar custos.
Exemplo:
Modelo de Gestão de Estoques para minimizar custos de armazenamento e pedido de produtos.
5. Aprendizado de máquina e inteligência artificial:
No aprendizado de máquina, a programação dinâmica é utilizada para otimizar algoritmos e encontrar ótimos globais.
Exemplo:
Algoritmos de aprendizado baseados em programação dinâmica, como o método de retropropagação em redes neurais.
GO TO FULL VERSION