Problema del vendedor ambulante: Python, C++ Algoritmo

ยฟQuรฉ es el problema del viajante (TSP)?

El problema del viajante (TSP) es un problema combinatorio clรกsico de la informรกtica teรณrica. El problema pide encontrar el camino mรกs corto en un grรกfico con la condiciรณn de visitar todos los nodos una sola vez y regresar a la ciudad de origen.

El planteamiento del problema proporciona una lista de ciudades junto con las distancias entre cada ciudad.

Objetivo: Para comenzar desde la ciudad de origen, visite otras ciudades solo una vez y regrese a la ciudad original nuevamente. Nuestro objetivo es encontrar el camino mรกs corto posible para completar la ruta de ida y vuelta.

Ejemplo de TSP

Aquรญ se proporciona un grรกfico donde 1, 2, 3 y 4 representan las ciudades, y el peso asociado con cada borde representa la distancia entre esas ciudades.

Ejemplo de TSP

El objetivo es encontrar el camino mรกs corto posible para el recorrido que comienza desde la ciudad de origen, atraviesa el grรกfico visitando las otras ciudades o nodos solo una vez y regresa a la ciudad de origen.

Para el grรกfico anterior, la ruta รณptima es seguir la ruta de costo mรญnimo: 1-2-4-3-1. Y esta ruta mรกs corta costarรญa 10+25+30+15 =80

Diferentes soluciones al problema del viajante

Diferentes soluciones al problema del viajante

El problema del viajante de comercio (TSP) se clasifica como un problema NP-hard debido a que no tiene un algoritmo de tiempo polinomial. La complejidad aumenta exponencialmente al aumentar el nรบmero de ciudades.

Hay varias formas de resolver el problema del viajante (cucharadita). Algunas soluciones populares son:

El enfoque de la fuerza bruta es el mรฉtodo ingenuo. para resolver problemas de vendedores ambulantes. En este enfoque, primero calculamos todos los caminos posibles y luego los comparamos. El nรบmero de caminos en un grรกfico que consta de n ciudades es n! Es computacionalmente muy costoso resolver el problema del viajante con este enfoque de fuerza bruta.

El mรฉtodo de ramificaciรณn y encuadernaciรณn: En este enfoque, el problema se divide en subproblemas. La soluciรณn de esos subproblemas individuales proporcionarรญa una soluciรณn รณptima.

Este tutorial demostrarรก un enfoque de programaciรณn dinรกmica, la versiรณn recursiva de este mรฉtodo de ramificaciรณn y vinculaciรณn, para resolver el problema del viajante.

Programaciรณn dinรกmica es un mรฉtodo de este tipo para buscar soluciones รณptimas analizando todas las rutas posibles. Es uno de los mรฉtodos de soluciรณn exactos que resuelven los problemas de los vendedores ambulantes a un costo relativamente mรกs alto que el mรฉtodos codiciosos que proporcionan una soluciรณn casi รณptima.

La complejidad computacional de este enfoque es O(norte^2 * 2^norte) que se analiza mรกs adelante en este artรญculo.

El mรฉtodo del vecino mรกs cercano es un enfoque voraz basado en heurรญsticas en el que elegimos el nodo vecino mรกs cercano. Este enfoque es computacionalmente menos costoso que el enfoque dinรกmico, pero no ofrece la garantรญa de una soluciรณn รณptima. Este mรฉtodo se utiliza para soluciones casi รณptimas.

Algoritmo para el problema del viajante

Utilizaremos el enfoque de programaciรณn dinรกmica para resolver el problema del viajante (TSP).

Antes de comenzar con el algoritmo, familiaricรฉmonos con algunas terminologรญas:

  • Un grรกfico G=(V, E), que es un conjunto de vรฉrtices y aristas.
  • V es el conjunto de vรฉrtices.
  • E es el conjunto de aristas.
  • Los vรฉrtices estรกn conectados a travรฉs de aristas.
  • Dist(i,j) denota la distancia no negativa entre dos vรฉrtices, i y j.

Supongamos que S es el subconjunto de ciudades y pertenece a {1, 2, 3,โ€ฆ, n} donde 1, 2, 3โ€ฆn son las ciudades e i, j son dos ciudades en ese subconjunto. Ahora el costo (i, S, j) se define de tal manera como la longitud del camino mรกs corto que visita el nodo en S, que tiene exactamente una vez el punto inicial y final como i y j respectivamente.

Por ejemplo, el costo (1, {2, 3, 4}, 1) denota la longitud del camino mรกs corto donde:

  • La ciudad inicial es 1.
  • Las ciudades 2, 3 y 4 se visitan solo una vez
  • El punto final es 1.

El algoritmo de programaciรณn dinรกmica serรญa:

  • Establezca el costo (i, , i) = 0, lo que significa que comenzamos y terminamos en i, y el costo es 0.
  • Cuando |S| > 1, definimos costo(i, S, 1) = โˆ donde i !=1 . Porque inicialmente, no sabemos el costo exacto para llegar de la ciudad i a la ciudad 1 a travรฉs de otras ciudades.
  • Ahora debemos comenzar en 1 y completar el recorrido. Necesitamos seleccionar la siguiente ciudad de tal manera:

costo(i, S, j)=costo mรญnimo (i, Sโˆ’{i}, j)+dist(i,j) donde iโˆˆS e iโ‰ j

Para la figura dada, la matriz de adyacencia serรญa la siguiente:

Algoritmo para el problema del viajante

dist(yo,j) 1 2 3 4
1 0 10 15 20
2 10 0 35 25
3 15 35 0 30
4 20 25 30 0

Veamos cรณmo funciona nuestro algoritmo:

Paso 1) Estamos considerando nuestro viaje comenzando en la ciudad 1, visitar otras ciudades una vez y regresar a la ciudad 1.

Paso 2) S es el subconjunto de ciudades. Segรบn nuestro algoritmo, para todo |S| > 1, fijaremos el coste de distancia (i, S, 1) = โˆ. Aquรญ, coste (i, S, j) significa que empezamos en la ciudad i, visitamos las ciudades de S una vez y ahora estamos en la ciudad j. Fijamos este coste de ruta como infinito porque aรบn no conocemos la distancia. Por tanto, los valores serรกn los siguientes:

Costo (2, {3, 4}, 1) = โˆ ; la notaciรณn indica que comenzamos en la ciudad 2, pasamos por las ciudades 3, 4 y llegamos a 1. Y el costo del camino es infinito. Similarmente-

costo(3, {2, 4}, 1) = โˆ

costo(4, {2, 3}, 1) = โˆ

Paso 3) Ahora, para todos los subconjuntos de S, necesitamos encontrar lo siguiente:

costo(i, S, j)=costo mรญnimo (i, Sโˆ’{i}, j)+dist(i,j), donde jโˆˆS e iโ‰ j

Eso significa la ruta de costo mรญnimo para comenzar en i, pasar por el subconjunto de ciudades una vez y regresar a la ciudad j. Considerando que el viaje comienza en la ciudad 1, el costo รณptimo del camino serรญa = costo(1, {otras ciudades}, 1).

Averigรผemos cรณmo podrรญamos lograrlo:

Ahora S = {1, 2, 3, 4}. Hay cuatro elementos. Por lo tanto, el nรบmero de subconjuntos serรก 2 ^ 4 o 16. Esos subconjuntos son:

1) |S| = Nulo:

{ฮฆ}

2) |S| = 1:

{{1}, {2}, {3}, {4}}

3) |S| = 2:

{{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}}

4) |S| = 3:

{{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {1, 3, 4}}

5) |S| = 4:

{{1, 2, 3, 4}}

Como comenzamos en 1, podrรญamos descartar los subconjuntos que contienen la ciudad 1.

El cรกlculo del algoritmo:

1) |S| =ฮฆ:

costo (2, ฮฆ, 1) = dist(2, 1) = 10

costo (3, ฮฆ, 1) = dist(3, 1) = 15

costo (4, ฮฆ, 1) = dist(4, 1) = 20

2) |S| = 1:

costo (2, {3}, 1) = dist(2, 3) + costo (3, ฮฆ, 1) = 35+15 = 50

costo (2, {4}, 1) = dist(2, 4) + costo (4, ฮฆ, 1) = 25+20 = 45

costo (3, {2}, 1) = dist(3, 2) + costo (2, ฮฆ, 1) = 35+10 = 45

costo (3, {4}, 1) = dist(3, 4) + costo (4, ฮฆ, 1) = 30+20 = 50

costo (4, {2}, 1) = dist(4, 2) + costo (2, ฮฆ, 1) = 25+10 = 35

costo (4, {3}, 1) = dist(4, 3) + costo (3, ฮฆ, 1) = 30+15 = 45

3) |S| = 2:

costo (2, {3, 4}, 1) = mรญnimo [ dist[2,3]+Costo(3,{4},1) = 35+50 = 85,

dist[2,4]+Costo(4,{3},1) = 25+45 = 70 ] = 70

costo (3, {2, 4}, 1) = mรญnimo [ dist[3,2]+Costo(2,{4},1) = 35+45 = 80,

dist[3,4]+Costo(4,{2},1) = 30+35 = 65 ] = 65

costo (4, {2, 3}, 1) = mรญnimo [ dist[4,2]+Costo(2,{3},1) = 25+50 = 75

dist[4,3]+Costo(3,{2},1) = 30+45 = 75 ] = 75

4) |S| = 3:

costo (1, {2, 3, 4}, 1) = min [ dist[1,2]+Costo(2,{3,4},1) = 10+70 = 80

dist[1,3]+Costo(3,{2,4},1) = 15+65 = 80

dist[1,4]+Costo(4,{2,3},1) = 20+75 = 95 ] = 80

Entonces la soluciรณn รณptima serรญa 1-2-4-3-1

Algoritmo para el problema del viajante

Pseudocรณdigo

Algorithm: Traveling-Salesman-Problem 
Cost (1, {}, 1) = 0 
for s = 2 to n do 
   for all subsets S belongs to {1, 2, 3, โ€ฆ , n} of size s 
      Cost (s, S, 1) = Infinity
   for all i ะ„ S and i โ‰  1 
      Cost (i, S, j) = min {Cost (i, S โ€“ {i}, j) + dist(i, j) for j ะ„ S and i โ‰  j} 
Return min(i) Cost (i, {1, 2, 3, โ€ฆ, n}, j) + d(j, i) 

Implantaciรณn en C/C++

Aquรญ estรก la implementaciรณn en C++:

#include <bits/stdc++.h>
using namespace std;
#define V 4
#define MAX 1000000
int tsp(int graph[][V], int s)
{
    vector<int> vertex;
    for (int i = 0; i < V; i++)
        if (i != s)
            vertex.push_back(i);
    int min_cost = MAX;
    while(next_permutation(vertex.begin(), vertex.end()))
     {
        int current_cost = 0;
        int j = s;
        for (int i = 0; i < vertex.size(); i++) {
            current_cost += graph[j][vertex[i]];
            j = vertex[i];
        }
        current_cost += graph[j][s];
        min_cost = min(min_cost, current_cost);
        return min_cost;
	}
}
int main()
{
    int graph[][V] = { { 0, 10, 15, 20 },{ 10, 0, 35, 25 },{ 15, 35, 0, 30 },{ 20, 25, 30, 0 } };                      
    int s = 0;
    cout << tsp(graph, s) << endl;
    return 0;
}

Salida:

80

Implementaciรณn en Python

from sys import maxsize
from itertools, import permutations
V = 4
def tsp(graph, s):
	vertex = []
	for i in range(V):
		if i != s:
			vertex.append(i)
    min_cost = maxsize
	next_permutation=permutations(vertex)
	for i in next_permutation:
		current_cost = 0
		k = s
		for j in i:
			current_cost += graph[k][j]
			k = j
		current_cost += graph[k][s]
		min_cost = min(min_cost, current_cost)
		return min_cost
graph = [[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]]
		s = 0
print(tsp(graph, s))

Salida:

80

Soluciones acadรฉmicas para TSP

Los informรกticos han pasado aรฑos buscando un algoritmo de tiempo polinรณmico mejorado para el problema del viajante. Hasta ahora, el problema sigue siendo NP-hard.

Aunque en los รบltimos aรฑos se han publicado algunas de las siguientes soluciones que han reducido la complejidad hasta cierto punto:

  • El TSP simรฉtrico clรกsico se resuelve mediante el mรฉtodo del sufijo cero.
  • El Algoritmo de Optimizaciรณn basado en Biogeografรญa se basa en la estrategia de migraciรณn para resolver los problemas de optimizaciรณn que se pueden planificar como TSP.
  • El algoritmo evolutivo multiobjetivo estรก diseรฑado para resolver mรบltiples TSP basados โ€‹โ€‹en NSGA-II.
  • El Sistema Multi-Agente resuelve el TSP de N ciudades con recursos fijos.

Aplicaciรณn del problema del viajante

El problema del viajante (TSP) se aplica en el mundo real tanto en su forma mรกs pura como modificada. Algunos de ellos son:

  • Planificaciรณn, logรญstica y fabricaciรณn de microchips.: Los problemas de inserciรณn de chips surgen naturalmente en la industria de los microchips. Esos problemas pueden planificarse como problemas de viajante de comercio.
  • secuencia ADN: Se puede utilizar una ligera modificaciรณn del problema del viajante en la secuenciaciรณn del ADN. Aquรญ, las ciudades representan los fragmentos de ADN y la distancia representa la medida de similitud entre dos fragmentos de ADN.
  • AstronomรญaLos astrรณnomos aplican el problema del viajante para minimizar el tiempo empleado en observar diversas fuentes.
  • Problema de control รณptimo: La formulaciรณn del problema del viajante se puede aplicar en problemas de control รณptimo. Es posible que se agreguen varias otras restricciones.

Anรกlisis de complejidad de TSP

  • Complejidad del tiempo: Hay un total de 2N subproblemas para cada nodo. Entonces el nรบmero total de subproblemas serรญa N*2N. Cada uno de los subproblemas requiere un tiempo lineal para resolverse. Si no se especifica el nodo de origen, tenemos que ejecutar bucles para N nodos.

    Por lo tanto, la complejidad temporal total para una soluciรณn รณptima serรญa la cantidad de nodos * cantidad de subproblemas * tiempo para resolver cada subproblema. La complejidad temporal se puede definir como O(N2 * 2^N).

  • Complejidad espacial: El enfoque de programaciรณn dinรกmica utiliza memoria para almacenar C(S, i), donde S es un subconjunto del conjunto de vรฉrtices. hay un total de 2N subconjuntos para cada nodo. Por lo tanto, la complejidad espacial es O(2^N).

A continuaciรณn, aprenderรก sobre Algoritmo del tamiz de Eratรณstenes

Resumir este post con: