Crear un programa de viajante de comercio, ¿las permutaciones son una buena técnica?

Estoy tratando de entender un programa TSP para la universidad, tengo que admitir que lo encuentro muy difícil.

Básicamente, tengo una matriz de valores Lat y una matriz de valores Lng, usando haversine, transfirí las distancias a una matriz.
Ahora, ¿a dónde ir desde aquí?
Tengo que encontrar la distancia más corta, visitando los 80 pueblos. Estoy tratando de pensar en la mejor manera de hacerlo. ¿Debo hacer un algoritmo de vecino más cercano? ¿Debo almacenar las permutaciones y sumar la distancia? ¿O hay un mejor camino? ¡Tengo que admitir que creo que esto es un poco difícil para un estudiante de primer año! De todos modos, aquí está mi código, es horrible, nos dieron el applet, etc.

public class Brain {

    //These are the names of the 80 towns and their north and west GPS co-ordinates

    static double north[] = {53.855,52.794,54.350,53.433,52.992,54.117,53.328,54.800,54.863,55.071,54.502,54.343,51.746,54.660,51.680,54.597,53.091,53.175,55.136,52.831,53.976,53.944,53.861,53.991,51.622,52.354,51.897,54.996,54.322,53.714,53.348,54.009,54.500,52.085,53.345,52.846,52.502,54.345,53.272,52.677,53.728,53.106,52.648,52.059,51.708,53.783,54.851,54.957,55.053,52.665,52.447,53.727,53.197,51.904,54.750,52.131,53.382,52.266,54.248,53.116,53.522,52.863,52.396,54.210,52.451,54.590,53.633,52.714,54.267,53.245,54.830,52.679,52.474,52.268,53.515,53.267,52.257,53.800,52.334,51.952};
    static double west[] = {-6.538,-6.165,-6.655,-7.950,-6.987,-9.167,-8.219,-7.790,-6.284,-6.508,-8.190,-6.260,-8.735,-5.670,-9.453,-5.930,-7.913,-6.525,-7.456,-6.932,-6.719,-8.095,-9.299,-7.360,-8.886,-7.712,-8.470,-7.307,-5.703,-6.350,-6.260,-6.405,-6.770,-7.640,-7.051,-8.981,-6.566,-7.640,-9.049,-6.292,-6.878,-6.065,-7.256,-9.507,-8.531,-8.917,-5.811,-7.720,-6.946,-8.624,-9.486,-7.800,-8.567,-8.957,-6.610,-8.642,-6.591,-8.270,-6.971,-7.324,-7.338,-8.200,-6.945,-5.882,-9.055,-7.290,-8.183,-8.869,-8.483,-9.306,-7.470,-7.814,-8.162,-9.696,-8.851,-7.500,-7.129,-9.533,-6.458,-7.846};
    String names[] = {"Ardee","Arklow","Armagh","Athlone","Athy","Ballina","Ballinasloe","Ballybofe","Ballymena","Ballymoney","Ballyshannon","Banbridge","Bandon","Bangor","Bantry","Belfast","Birr","Blessington","Buncrana","Carlow","Carrickmacross","Carrick-On-Shannon","Castlebar","Cavan","Clonakilty","Clonmel","Cork","Derry","Downpatrick","Drogheda","Dublin","Dundalk","Dungannon","Dungarvan","Edenderry","Ennis","Enniscorthy","Enniskillen","Galway","Gorey","Kells","Kilcoole","Kilkenny","Killarney","Kinsale","Knock","Larne","Letterkenny","Limavady","Limerick","Listowel","Longford","Loughrea","Macroom","Magherafelt","Mallow","Maynooth","Mitchelstown","Monaghan","Mountmellick","Mullingar","Nenagh","New-Ross","Newcastle","Newcastle-West","Omagh","Roscommon","Shannon","Sligo","Spiddal","Strabane","Thurles","Tipperary","Tralee","Tuam","Tullamore","Waterford","Westport","Wexford","Youghal"};
    static double[][] matrix = new double[80][80];
    boolean visit[]=new boolean[80];
    boolean valid = true;

    public static void fillmatrix (){
        double tote = 0;
        for(int i=1;i<80;i++){
            for(int j=1;j<80;j++){
                matrix[i][j]=getDistance(north[i],west[j],north[j],west[j]);
            }
        }
    }

    public String compute () {          
        String solution ="";
        for (int i=0;i<80;i++){
            solution+=(char)(i+40);
        }
        solution+="Anything you add on after the 80 characters will be " + 
            "printed in the textbox (e.g. you can compute the distance)";
        return solution;    
    }

    public static double getDistance(double lat1, double lon1, double lat2, double lon2){
        double R = 6371;
        double dLat = Math.toRadians((lat2-lat1));
        double dLon = Math.toRadians((lon2-lon1)); 
        double a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
            Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
            Math.sin(dLon/2) * Math.sin(dLon/2); 
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
        double d = R * c;         
        return d;
    }    
}

preguntado el 03 de mayo de 12 a las 18:05

¡Si hay 80 ciudades, eso significa que hay aproximadamente 80! (10^ 118) permutaciones! -

3 Respuestas

La mejor manera de abordar la heurística del vecino más cercano es dividir el algoritmo en subproblemas.

  1. Seleccione una ciudad al azar.
  2. Encuentra la ciudad no visitada más cercana y ve allí.
  3. ¿Quedan ciudades sin visitar? Si es así, repita el paso 2.
  4. Vuelve a la primera ciudad.

A continuación, resuelve cada subproblema.

  1. Elija un valor aleatorio en la matriz de nombres
  2. Verifique la distancia de todas las ciudades a la ciudad aleatoria iterando a través de la matriz norte y oeste y calculando la distancia. Almacene las ciudades visitadas en una matriz.
  3. Repita 2
  4. Regreso a la primera ciudad

Luego, piense en el pseudocódigo e intente escribir el código Java.

contestado el 03 de mayo de 12 a las 18:05

Verificar todas las permutaciones será prohibitivamente costoso para cualquier cosa excepto para las instancias más pequeñas.

Afortunadamente, hay un montón de algoritmos heurísticos bien conocidos para el TSP. Elige tu opción.

Respondido el 25 de enero de 14 a las 17:01

Sí, estaba pensando en el vecino más cercano, no tengo idea de cómo implementarlibros de éxitos - Leah Buchanan

El enlace está muerto, ¿quieres dar más detalles? - Jack

Acerca del código fuente

Al principio, podría recomendarle que cambie la definición de las coordenadas de una ciudad a la clase Ciudad y, como sus ciudades están predefinidas, es posible que desee 'exportarla' en un archivo externo y cargarlo al principio del archivo. Por ejemplo,

public class City{
    public double North;
    public double West;
    public String Name;
    public double getDistanceToCity(City target){
        double R = 6371;
        double dLat = Math.toRadians((target.North-this.North));
        double dLon = Math.toRadians((target.West-this.West)); 
        double a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
            Math.cos(Math.toRadians(this.North)) * Math.cos(Math.toRadians(this.West)) *
            Math.sin(dLon/2) * Math.sin(dLon/2); 
        double d = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));         
        return d;}}

Luego, por ejemplo, después de leer su archivo en "ArrayList Cities", creará su matriz de la siguiente manera:

double[][] distances = new double[Cities.size()][Cities.size()];
int i=0;
int j=0;
for(City start:Cities){
    for(City end:Cities){
        distances[i][j]=start.getDistanceToCity(end);
        j++;}
    i++;}

Y obtener la misma matriz. En este caso, puede cambiar el tamaño de los datos de entrada, por ejemplo, probar la corrección de su algoritmo con 10 ciudades y, después de todo, funciona bien con 80. Además, en este caso verá por sí mismo la dificultad de este problema, simplemente ejecutarlo en 40 y 41 ciudad...

A continuación, sobre algo...

Este es un problema NP-difícil, por lo que sus permutaciones funcionarán MUCHO tiempo. Sugeriré el algoritmo Held-Karp, que es mucho más rápido pero bastante difícil de realizar y necesita mucha memoria. (Por ejemplo, método sugerido si (n*n*2^n), que es 10^27 para n=80, y las permutaciones son n!, que 10^121 para n=80 - me refiero a las operaciones requeridas para resolver la tarea) .

De cualquier manera, la mejor solución exacta por ahora es la programación lineal (no recuerdo el método exacto, pero...). Puede que encuentre algo que considere usar métodos gráficos.

contestado el 04 de mayo de 12 a las 15:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.