Branch and Bound
Definição
Branch and Bound é uma técnica de busca usada para resolver problemas de otimização combinatória, onde o objetivo é encontrar a melhor solução possível (não apenas uma solução válida). Ao contrário do backtracking, que visa encontrar qualquer solução válida, o Branch and Bound busca sempre a melhor — e evita caminhos improdutivos com base em limites.
Ela combina:
- Branching: divisão do problema em subproblemas menores (como no backtracking);
- Bounding: cálculo de limites (bounds) para evitar explorar caminhos que não podem levar à solução ótima.
Se um ramo não puder melhorar a melhor solução já encontrada, ele é descartado — isso reduz drasticamente o espaço de busca.
Por que usar
- Ideal para problemas em que todas as combinações possíveis são muito numerosas (exponenciais);
- Mais eficiente que backtracking puro em problemas de otimização;
- Garante a melhor solução, sem precisar testar todas as possibilidades.
Exemplos clássicos
- Problema do Caixeiro Viajante (TSP);
- Mochila Inteira (0/1);
- Alocação de tarefas com custo mínimo;
- Programação inteira.
Complexidade
- Pode chegar a tempo exponencial, mas melhora muito com bons limites (bounds);
- Depende de estratégias de poda e heurísticas para eficiência.
Exemplo prático (Python) — Mochila 0/1 com poda
Este código resolve o problema da mochila 0/1, buscando o maior valor possível de itens que caibam na mochila. Usa a técnica de Branch and Bound para evitar caminhos que não podem levar à melhor solução.
# Classe que representa um item com valor e peso
class Item:
    def __init__(self, valor, peso):
        self.valor = valor
        self.peso = peso
        self.densidade = valor / peso
# Resolve o problema da mochila 0/1 com Branch and Bound
def mochila_branch_and_bound(capacidade, itens):
    itens.sort(key=lambda x: x.densidade, reverse=True)
    melhor_valor = 0
    # Função recursiva que explora as decisões
    def explorar(indice, valor_atual, peso_atual):
        nonlocal melhor_valor
        if peso_atual > capacidade:
            return  # Excede a capacidade, descarta
        if valor_atual > melhor_valor:
            melhor_valor = valor_atual
        if indice >= len(itens):
            return  # Todos os itens foram considerados
        # Cálculo do limite otimista (bound)
        restante = capacidade - peso_atual
        estimativa = valor_atual
        i = indice
        while i < len(itens) and restante > 0:
            if itens[i].peso <= restante:
                estimativa += itens[i].valor
                restante -= itens[i].peso
            else:
                estimativa += itens[i].densidade * restante
                break
            i += 1
        if estimativa < melhor_valor:
            return  # Poda: não vale a pena continuar
        # Explora com e sem incluir o item atual
        explorar(indice + 1, valor_atual + itens[indice].valor, peso_atual + itens[indice].peso)
        explorar(indice + 1, valor_atual, peso_atual)
    explorar(0, 0, 0)
    return melhor_valor
# Exemplo
itens = [
    Item(valor=60, peso=10),
    Item(valor=100, peso=20),
    Item(valor=120, peso=30)
]
capacidade = 50
resultado = mochila_branch_and_bound(capacidade, itens)
print("Melhor valor possível:", resultado)  # Saída esperada: 220
Saída
Melhor valor possível: 220
 ECOSSISTEMA PYTHON
 ECOSSISTEMA PYTHON  LINUX
 LINUX  ASSEMBLY NASM
 ASSEMBLY NASM  JAVA
 JAVA