如何在我的旅行推销员计划中完成每个排列?

时间:2018-04-14 00:27:17

标签: java recursion traveling-salesman

我正在努力研究旅行商问题(TSP)的变化,并且我遇到了一个让我挠头的减速带。我必须找到访问全球1000所顶尖大学的最短路程。

起点和终点是相同的位置。此外,一个人只能前往100级以内的大学。

我非常确定我的代码可以解决这个问题的一次随机迭代,但是我无法想出让我的代码运行它的每一个可能的排列的方法。

如果有人能提供任何见解,我们将非常感激。

import java.io.BufferedReader;
import java.util.*;
import java.math.*;

public class Travelling {
    public static String[] contents;
    public static College maynooth;
    public static String[] colleges;
    public static double[] longitude=new double[1000];
    public static double[] latitude=new double[1000];
    public static int[] ranks=new int[1000];
    public static LinkedList unis=new LinkedList();
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        FileIO reader = new FileIO();
        contents = reader.load("universities.txt");
        boolean[] visited=new boolean[1000];
        double startingDistance=0.0;
        for(int i=0;i<visited.length;i++){
            visited[i]=false;
        }   
        for(int j=0;j<contents.length;j++){
            String[] temp=contents[j].split(" ");
            for(int i=0;i<temp.length;i++){
                ranks[j]=j+1;
                temp[i]=temp[i].replaceAll("\\s","");
                double longTemp=Double.parseDouble(temp[temp.length-1]);
                longitude[j]=longTemp;
                double latTemp=Double.parseDouble(temp[temp.length-2]);
                latitude[j]=latTemp;

            }

        }
        List<College> allColleges=new ArrayList<College>();
        for(int i=0;i<1000;i++){
            College tempCollege=new College();
            tempCollege.rank=ranks[i];
            tempCollege.lat=latitude[i];
            tempCollege.lon=longitude[i];
            tempCollege.currentIndex=i;
            allColleges.add(tempCollege);
        }
        maynooth=allColleges.get(607);
        distToUni(startingDistance, allColleges.get(607),allColleges);
        unis.display();
    }

    public static Double distanceBetweenTwoLocationsInKm(Double lat1, Double lon1, Double lat2, Double lon2) {
        if (lat1 == null || lat2 == null || lon1 == null || lon2 == null) {
            return null;
        }

        double earthRadius = 6371.0d;
        double diffBetweenLatitudeRadians = Math.toRadians(lat2 - lat1);
        double diffBetweenLongitudeRadians = Math.toRadians(lon2 - lon1);
        double latitudeOneInRadians = Math.toRadians(lat1);
        double latitudeTwoInRadians = Math.toRadians(lat2);
        double a = Math.sin(diffBetweenLatitudeRadians / 2) * Math.sin(diffBetweenLatitudeRadians / 2) + Math.cos(latitudeOneInRadians) * Math.cos(latitudeTwoInRadians) * Math.sin(diffBetweenLongitudeRadians / 2)
                * Math.sin(diffBetweenLongitudeRadians / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return (earthRadius * c);
    }

    public static void distToUni(double distance,College firstCollege, List<College> currentColleges){   
        Random randGen=new Random();
        currentColleges.remove(firstCollege);
        for(int i=0;i<currentColleges.size();i++){
            currentColleges.get(i).currentIndex=i;
        }

        List<College> upperList=new ArrayList<College>();
        List<College> lowerList=new ArrayList<College>();

        int upperIndex=firstCollege.currentIndex+1;
        int lowerIndex=(currentColleges.get(firstCollege.currentIndex).currentIndex)-1;
        while((upperIndex<currentColleges.size()-1) && (currentColleges.get(upperIndex)!=null) && (((currentColleges.get(upperIndex).rank)-(currentColleges.get(firstCollege.currentIndex).rank))<100)){
            upperList.add(currentColleges.get(upperIndex));
            upperIndex++;
        }
        while((lowerIndex>=0)&&(currentColleges.get(firstCollege.currentIndex)!=null)&&((currentColleges.get(lowerIndex).rank)-(currentColleges.get(firstCollege.currentIndex).rank)>-100)){
            lowerList.add(currentColleges.get(lowerIndex));
            lowerIndex--;
        }

        List<College> combined=new ArrayList<College>();

        Collections.reverse(lowerList);
        combined.addAll(lowerList);
        combined.addAll(upperList);
        int randIndex = 0;
        if(combined.size()==1){
            College lastCollege = new College();
            lastCollege=combined.get(0);
            distance+=distanceBetweenTwoLocationsInKm(maynooth.lat, maynooth.lon, lastCollege.lat, lastCollege.lon);
        }
        if(combined.size() == 0) {
            unis.insertHead(distance);
            return; 
        }

        try {
            randIndex = randGen.nextInt(combined.size());
            double tempDist=distanceBetweenTwoLocationsInKm(firstCollege.lat, firstCollege.lon, combined.get(randIndex).lat, combined.get(randIndex).lon);
            distance=distance+tempDist;
        } catch (IllegalArgumentException ex) {}

        College currentCollege = new College();
        try {
            currentCollege = combined.get(randIndex);
        } catch(IndexOutOfBoundsException ex) {}
        distToUni(distance, currentCollege, currentColleges);

        return;
    }

}

1 个答案:

答案 0 :(得分:0)

我可以想到几个可能的加速。

a)在飞机世界中,我们经常有距离和毕达哥拉斯类似的距离问题:a²+b²=c²,因此c = math.sqrt(a a + b b)。但是math.sqrt的成本非常高。但是为了比较两个距离,我们不需要知道实际距离 - 如果c1&lt; c2,然后c1²&lt; c2²,反之亦然。所以不要计算平方根。 类似的想法:地球弯曲在每个位置几乎都是恒定的,你也没有使用它的任何缩写,所以以km为单位的距离与比较2个距离无关。但是,

b)距离永远不会改变。对于1000所大学,有1000 * 1000个距离,但由于d(a,b)= d(b,a),它只有500.000。减去1000,因为d(a,a)为0并且没有意思。

但是你只需要等级为100的那些人的距离,所以对于那些排名最低的人来说,排名更高的100人,排名更低的100人,中间人200人,每个方向100人。 。作为上限,稀疏阵列中的200 * 200/2 = 20.000距离,其中每0表示该大学不在等级范围内。

这些只需要计算一次。

但是      200 * 199 * 199 * ...... * 199 * 199 * 198 * 198 * 197 * ... 3 * 3 * 2 * 2        (1000-200)案例 - &gt; ^ | &lt; - 200例

仍然是一个非常非常大的数字来迭代(即使一些约200s只有100s,因为它们接近排名的底部或顶部)。

Imho你应该将你的代码分成更小的函数,以改进更高抽象级别的代码推理。也许那时你不需要评论它,因为这些名字足以说明。

否则您的代码需要注释,如何解决问题。

我只知道找到相当不错的算法,但运气是平面形状上没有等级限制的最佳解决方案。你随机取3分(ABC)并将它们组合起来。现在,您通过随机迭代地再添加一个点D,并通过搜索点对(AB),(BC),(CA),其中插入D具有最小成本(ADB),(BDC),(CDA)。必须重复这一点,直到将所有点添加到链中。

对于最后一个元素,你已经有999个顶点并且必须检查999才能找到最便宜的插入,但是它受到排名的限制,所以它只有大约200个链来进行比较。

这是200 + 200 + 200 + .... + 199 + 198 + 198 ... + 3 + 3 + 2 + 2 + 1 + 1或低于200.000比较,以及距离表,这个应该加速大规模。然后你可以运行这个随机选择几千次,以获得一个非常好的结果 - 但它不能保证绝对最佳。