Universidade Federal do Piauí
Um caixeiro precisa visitar n cidades exatamente uma vez cada e voltar para a cidade de origem, percorrendo a menor distância (ou custo) total possível.
É representado como um grafo completo ponderado (todas as cidades têm ligação direta com todas as outras, com um custo/distância).
O objetivo é encontrar o ciclo hamiltoniano de menor custo.
Algoritmo: Caixeiro Viajante
Entrada: Matriz de distâncias entre n elementos.
Inicializar:
Conjunto de pontos = {1,2,...,n}
MelhorCusto=∞
MelhorRota=[ ]
Para cada permutação P de pontos:
a. Calcular Custo(P)
b. Se Custo(P)<MelhorCusto:
MelhorCusto=Custo(P)
O problema foi modelado como um grafo completo \(G=(V,E)\), onde:
As coordenadas geográficas de cada capital foram utilizadas para calcular as distâncias entre os vértices por meio da fórmula de Haversine(D), que permite estimar a distância entre dois pontos na superfície terrestre.
\[ d = 2R \arcsin \left( \sqrt{ \sin^2 \left( \frac{\varphi_2 - \varphi_1}{2} \right) + \cos(\varphi_1) \cos(\varphi_2) \sin^2 \left( \frac{\lambda_2 - \lambda_1}{2} \right) } \right) \]
Dessa forma, o grafo gerado é:
A abordagem segue os seguintes passos:
Fixação da cidade inicial (Brasília);
Geração de todas as permutações possíveis das demais capitais;
Construção das rotas completas (ida e volta);
Cálculo da distância total de cada rota;
Seleção da rota com menor custo
Configurações do máquina usada:
print("=" * 70)
print("CAIXEIRO VIAJANTE - FORÇA BRUTA COM TEMPO LIMITE")
print("=" * 70)
print("\n[1] Carregando matriz de distâncias...")
matriz = pd.read_csv(ARQUIVO_CSV, index_col=0)
print(f"Arquivo carregado! Total de capitais disponíveis: {len(matriz)}")
print("\n[2] Selecionando capitais mais próximas...")
distancias_brasilia = matriz.loc[CAPITAL_INICIAL].drop(CAPITAL_INICIAL)
capitais_proximas = distancias_brasilia.sort_values().head(QUANTIDADE_CAPITAIS)
capitais_para_visitar = list(capitais_proximas.index)
for i, capital in enumerate(capitais_para_visitar, start=1):
print(f"{i}. {capital} - {capitais_proximas[capital]} km de Brasília")
total_possibilidades = math.factorial(QUANTIDADE_CAPITAIS)
print(f"\nTotal de rotas possíveis: {total_possibilidades:,}")print("\n[4] Iniciando busca por força bruta...")
tempo_limite_segundos = TEMPO_LIMITE_MINUTOS * 60
inicio_tempo = time.time()
menor_distancia = float("inf")
melhor_rota = None
rotas_testadas = 0
for rota_permutada in itertools.permutations(capitais_para_visitar):
tempo_atual = time.time()
tempo_decorrido = tempo_atual - inicio_tempo
# Condição de parada por tempo
if tempo_decorrido >= tempo_limite_segundos:
print("\nTempo limite atingido.")
break
# Monta a rota completa: Brasília -> Capitais -> Brasília
rota_completa = [CAPITAL_INICIAL] + list(rota_permutada) + [CAPITAL_INICIAL]
distancia_total = calcular_distancia_rota(rota_completa, matriz)
rotas_testadas += 1
# Atualiza se encontrar uma rota mais curta
if distancia_total < menor_distancia:
menor_distancia = distancia_total
melhor_rota = rota_completa
print(f"\nNova melhor rota encontrada! Distância: {menor_distancia:.2f} km")
print(" -> ".join(melhor_rota))
# Log de progresso a cada 10.000 iterações
if rotas_testadas % 10000 == 0:
percentual = (rotas_testadas / total_possibilidades) * 100
print(f"Progresso: {percentual:.4f}% | Testadas: {rotas_testadas:,}")O algoritmo de força bruta possui complexidade temporal:
\[ O(n!) \]
É necessário calcular a soma das distâncias entre as cidades, o que possui custo:
\[ O(n) \]
Assim, a complexidade total pode ser representada como:
\[ O(n . n!) \]
| Teste | Nº de Capitais | Nº de Possibilidades | Rotas Testadas | % do Espaço | Tempo (s) |
|---|---|---|---|---|---|
| 1 | 5 | 120 | 120 | 100% | 0,01 |
| 2 | 8 | 40.320 | 40.320 | 100% | 2,09 |
| 3 | 9 | 362.880 | 362.880 | 100% | 21,27 |
| 4 | 10 | 3.628.800 | 3.628.000 | 100% | 232,53 |
| 5 | 13 | 6.227.020.800 | 20.892.479 | 0,3355% | 1.800 |
| 6 | 27 | 1,09 × 10²⁸ | 67.081.582 | ~0,0000% | 10.800 |
Podemos estimar a taxa média de processamento: Exemplo (teste 13 capitais):
\[ \frac{20892479}{1800} = 11606 \text{ rotas/segundo} \]
Mesmo com essa taxa seriam necessários bilhões de anos para explorar todo o espaço das 27 capitais.
Mestrado em Ciência da Computação