我正在努力研究旅行商问题(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;
}
}
答案 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比较,以及距离表,这个应该加速大规模。然后你可以运行这个随机选择几千次,以获得一个非常好的结果 - 但它不能保证绝对最佳。