计算Java中TSP的地理距离和欧氏距离

时间:2014-02-19 12:36:30

标签: java math coordinates distance euclidean-distance

基本上我使用的是TSPLIB的数据,我有这个规格。

这就是我计算欧氏距离的方法(根据上面的规范):

public static double calculateDistance(double x1, double y1, double x2, double y2){
    double xDistance = Math.abs(x1 - x2);
    double yDistance = Math.abs(y1 - y2);
    double distance = Math.sqrt( (xDistance*xDistance) + (yDistance*yDistance) );

    return distance;
}

这是我计算地理距离的方式(根据上面的规范):

public static double calculateGeoDistance(double lat1, double lon1, double lat2, double lon2) {
    double lat1Rad = coordinates2Radians(lat1);
    double lat2Rad = coordinates2Radians(lat2);
    double lon1Rad = coordinates2Radians(lon1);
    double lon2Rad = coordinates2Radians(lon2);

    double R = 6378.388;

    double q1 = Math.cos(lon1Rad - lon2Rad);
    double q2 = Math.cos(lat1Rad - lat2Rad);
    double q3 = Math.cos(lat1Rad + lat2Rad);

    double distance = (R * Math.acos(0.5 * ((1.0 + q1) * q2 - (1.0 - q1) * q3)) + 1.0);
    return distance;
}

private static double coordinates2Radians(double coordinate) {
    double deg = Math.round(coordinate);
    double min = coordinate - deg;
    double rad = Math.PI * (deg + 5.0 * min / 3.0) / 180.0;
    return rad;
}

但是这个问题是我得到的结果低于TSPLIB最优(不可能!)。我的计算有问题吗?我已经尝试使用预定义的数据和距离来计算最优,我确实得到了最优,我不知道为什么这不起作用..

非常感谢。

3 个答案:

答案 0 :(得分:0)

你转换为弧度看起来很可疑。我会尝试:

private static double coordinates2Radians(double coordinate) {
    return Math.PI * coordinate / 180.0;
}

另外,我会在上面评论中提到的Movable Type网站上使用公式。

答案 1 :(得分:0)

这可能对您阅读TSPLIB的常见问题

有所帮助

http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/TSPFAQ.html

检查问:GEO类型的问题我得错了。

我遵循了该实现,而不是TSPLIB 95规范中列出的内容。我的实现(在Groovy中):

static int[][] distancesInGEO(List nodes) {
    int dim = nodes.size();
    double[] latitude = new double[dim];
    double[] longitude = new double[dim];

    final double PI = 3.141592;
    for (int i = 0; i < dim; i++) {
        int deg = (int) (nodes[i].x);
        double min = nodes[i].x - deg;
        latitude[i] = PI * (deg + 5 * min / 3) / 180;
        deg = (int) nodes[i].y;
        min = nodes[i].y - deg;
        longitude[i] = PI * (deg + 5 * min / 3) / 180;
    }

    int[][] d = new int[dim][dim];

    final double RRR = 6378.388;
    for (int i = 0; i < dim; i++)
        for (int j = i + 1; j < dim; j++) {
            double q1 = cos(longitude[i] - longitude[j]);
            double q2 = cos(latitude[i] - latitude[j]);
            double q3 = cos(latitude[i] + latitude[j]);
            d[i][j] = (int) (RRR * acos(0.5 * ((1.0 + q1) * q2 - (1.0 - q1) * q3)) + 1.0);
            d[j][i] = d[i][j];
        }
    return d;
}

我猜测您的问题是由于遵循规范并使用nint计算学位而产生的。但那确实是错的。例如,输入10.53表示10度和53分钟。但是如果你使用nint来围绕10.53,那么你将获得11度,并且随后的分钟计算也将是错误的。

答案 2 :(得分:0)

我遇到了类似的问题,并且有点恼火,因为两个地理点之间的距离计算偏差超过两倍,如果仔细选择四舍五入程序就不会发生这种情况。

在这里找到:

  • ulysses16.tsp的3种不同计算方式(TSPLIB文件,TSPLIB常见问题和实际距离)
  • 所有解决方案的最佳解决方案和数据
  • java中用于计算距离的代码

分析下面的距离时,您会发现明显的差异,例如在第14点和第13点之间,范围从52 km(FAQ)到122 km(docu),真相约73 km。这可能会导致不同的最佳解决方案。

问题发生在将度四舍五入为整数(最小或数学)。

弧度中的第14点:
常见问题解答:0.660607,0.266744-> 37.85,15.28
纪录片:0.648971、0.266744-> 37.18、15.28
实数:0.654673、0.264766-> 37.51、15.17

在四舍五入的FAQ位置和Docu位置之间,大约有50公里!

TSPLIB ulysses16.tsp FAQ as graphic by Gunnar Bernstein

Ulysses16 calculated according to the FAQ (should be used to compare results with TSPLIB optimal solutions):

TSP-Tour Optimal:
Location ID: 1 (38,24|20,42), in Radians: Latitude: 0,670206, Longitude: 0,361283
Location ID: 14 (37,51|15,17), in Radians: Latitude: 0,660607, Longitude: 0,266744
Location ID: 13 (38,15|15,35), in Radians: Latitude: 0,667588, Longitude: 0,271980
Location ID: 12 (38,47|15,13), in Radians: Latitude: 0,676897, Longitude: 0,265581
Location ID: 7 (38,42|13,11), in Radians: Latitude: 0,675442, Longitude: 0,230093
Location ID: 6 (37,56|12,19), in Radians: Latitude: 0,662061, Longitude: 0,214966
Location ID: 15 (35,49|14,32), in Radians: Latitude: 0,625119, Longitude: 0,253654
Location ID: 5 (33,48|10,54), in Radians: Latitude: 0,589921, Longitude: 0,190241 TP Hull
Location ID: 11 (36,08|-5,21), in Radians: Latitude: 0,630646, Longitude: -0,093375 TP Hull
Location ID: 9 (41,23|9,10), in Radians: Latitude: 0,722275, Longitude: 0,159988 TP Hull
Location ID: 10 (41,17|13,05), in Radians: Latitude: 0,720530, Longitude: 0,228347 TP Hull
Location ID: 16 (39,36|19,56), in Radians: Latitude: 0,691150, Longitude: 0,347902
Location ID: 3 (40,56|25,32), in Radians: Latitude: 0,714421, Longitude: 0,445641 TP Hull
Location ID: 2 (39,57|26,15), in Radians: Latitude: 0,697259, Longitude: 0,458149 TP Hull
Location ID: 4 (36,26|23,12), in Radians: Latitude: 0,635881, Longitude: 0,404916 TP Hull
Location ID: 8 (37,52|20,44), in Radians: Latitude: 0,660898, Longitude: 0,361865

Distances:
From 1 to 14: 479,0
From 14 to 13: 52,0
From 13 to 12: 68,0
From 12 to 7: 177,0
From 7 to 6: 115,0
From 6 to 15: 308,0
From 15 to 5: 401,0
From 5 to 11: 1.504,0
From 11 to 9: 1.387,0
From 9 to 10: 328,0
From 10 to 16: 610,0
From 16 to 3: 499,0
From 3 to 2: 126,0
From 2 to 4: 474,0
From 4 to 8: 271,0
From 8 to 1: 60,0
Total: 6.859,0

TSPLIB ulysses16.tsp graphic new optimum by Gunnar Bernstein

Ulysses16 calculated according to the manual tsp95.pdf. 
Because of the different distance calculation now a better optimum can be found.

TSP-Tour (not) Optimal (given optimal tour by TSPLIB):
Location ID: 1 (38,24|20,42), in Radians: Latitude: 0,670206, Longitude: 0,361283
Location ID: 14 (37,51|15,17), in Radians: Latitude: 0,648971, Longitude: 0,266744
Location ID: 13 (38,15|15,35), in Radians: Latitude: 0,667588, Longitude: 0,271980
Location ID: 12 (38,47|15,13), in Radians: Latitude: 0,676897, Longitude: 0,265581
Location ID: 7 (38,42|13,11), in Radians: Latitude: 0,675442, Longitude: 0,230093
Location ID: 6 (37,56|12,19), in Radians: Latitude: 0,650426, Longitude: 0,214966
Location ID: 15 (35,49|14,32), in Radians: Latitude: 0,625119, Longitude: 0,253654
Location ID: 5 (33,48|10,54), in Radians: Latitude: 0,589921, Longitude: 0,178605 TP Hull
Location ID: 11 (36,08|-5,21), in Radians: Latitude: 0,630646, Longitude: -0,093375 TP Hull
Location ID: 9 (41,23|9,10), in Radians: Latitude: 0,722275, Longitude: 0,159988 TP Hull
Location ID: 10 (41,17|13,05), in Radians: Latitude: 0,720530, Longitude: 0,228347 TP Hull
Location ID: 16 (39,36|19,56), in Radians: Latitude: 0,691150, Longitude: 0,336267
Location ID: 3 (40,56|25,32), in Radians: Latitude: 0,702786, Longitude: 0,445641 TP Hull
Location ID: 2 (39,57|26,15), in Radians: Latitude: 0,685623, Longitude: 0,458149 TP Hull
Location ID: 4 (36,26|23,12), in Radians: Latitude: 0,635881, Longitude: 0,404916 TP Hull
Location ID: 8 (37,52|20,44), in Radians: Latitude: 0,649262, Longitude: 0,361865

Distances:
From 1 to 14: 496,0
From 14 to 13: 122,0
From 13 to 12: 68,0
From 12 to 7: 177,0
From 7 to 6: 177,0
From 6 to 15: 256,0
From 15 to 5: 453,0
From 5 to 11: 1.444,0
From 11 to 9: 1.387,0
From 9 to 10: 328,0
From 10 to 16: 557,0
From 16 to 3: 540,0
From 3 to 2: 126,0
From 2 to 4: 416,0
From 4 to 8: 236,0
From 8 to 1: 134,0
Total: 6.917,0

TSP-Tour (real) Optimal (brute force calculated):
Distances:
From 1 to 3: 466,0
From 3 to 2: 126,0
From 2 to 4: 416,0
From 4 to 8: 236,0
From 8 to 14: 484,0
From 14 to 15: 167,0
From 15 to 6: 256,0
From 6 to 5: 430,0
From 5 to 11: 1.444,0
From 11 to 9: 1.387,0
From 9 to 10: 328,0
From 10 to 7: 288,0
From 7 to 12: 177,0
From 12 to 13: 68,0
From 13 to 16: 353,0
From 16 to 1: 183,0
Total: 6.809,0

-

TSP-Tour Optimal (real distances, but optimum like FAQ optimum):
Location ID: 1 (38,24|20,42), in Radians: Latitude: 0,667414, Longitude: 0,356396
Location ID: 14 (37,51|15,17), in Radians: Latitude: 0,654673, Longitude: 0,264766
Location ID: 13 (38,15|15,35), in Radians: Latitude: 0,665843, Longitude: 0,267908
Location ID: 12 (38,47|15,13), in Radians: Latitude: 0,671428, Longitude: 0,264068
Location ID: 7 (38,42|13,11), in Radians: Latitude: 0,670555, Longitude: 0,228813
Location ID: 6 (37,56|12,19), in Radians: Latitude: 0,655546, Longitude: 0,212756
Location ID: 15 (35,49|14,32), in Radians: Latitude: 0,619417, Longitude: 0,249931
Location ID: 5 (33,48|10,54), in Radians: Latitude: 0,584336, Longitude: 0,183958 TP Hull
Location ID: 11 (36,08|-5,21), in Radians: Latitude: 0,629715, Longitude: -0,090932 TP Hull
Location ID: 9 (41,23|9,10), in Radians: Latitude: 0,719599, Longitude: 0,158825 TP Hull
Location ID: 10 (41,17|13,05), in Radians: Latitude: 0,718552, Longitude: 0,227765 TP Hull
Location ID: 16 (39,36|19,56), in Radians: Latitude: 0,686962, Longitude: 0,341386
Location ID: 3 (40,56|25,32), in Radians: Latitude: 0,707906, Longitude: 0,441917 TP Hull
Location ID: 2 (39,57|26,15), in Radians: Latitude: 0,690627, Longitude: 0,456404 TP Hull
Location ID: 4 (36,26|23,12), in Radians: Latitude: 0,632856, Longitude: 0,403520 TP Hull
Location ID: 8 (37,52|20,44), in Radians: Latitude: 0,654848, Longitude: 0,356745

Distances:
From 1 to 14: 468,4
From 14 to 13: 73,0
From 13 to 12: 40,5
From 12 to 7: 176,2
From 7 to 6: 125,2
From 6 to 15: 299,0
From 15 to 5: 412,7
From 5 to 11: 1.467,2
From 11 to 9: 1.367,5
From 9 to 10: 330,9
From 10 to 16: 588,4
From 16 to 3: 509,2
From 3 to 2: 130,9
From 2 to 4: 454,5
From 4 to 8: 276,8
From 8 to 1: 80,2
Total: 6.800,5

-

        // y and x are flipped, because latitude is given first, which graphically is y
        // rounding degree to int is problematic
        // part of constructor, you figure it out
        this.x = y; // y = longitude in degrees from file
        this.y = x; // x = latitude in degrees from file
        // calcRadians();
        if (USE_TSPLIB_CALC) {
            // https://www.iwr.uni-heidelberg.de/groups/comopt/software/TSPLIB95/tsp95.pdf
            final double PI = 3.141592;
            int degree;
            if (USE_TSPLIB_CALC_FAQ)
                degree = (int) this.y; // FAQ int to floor
            else
                degree = (int) Math.round(this.y);
            double min = this.y - degree;
            this.latitudeRadians = PI * (degree + 5 * min / 3d) / 180d;
            if (USE_TSPLIB_CALC_FAQ)
                degree = (int) this.x; // FAQ int to floor
            else
                degree = (int) Math.round(this.x); // tsp95.doc nearest int
            min = this.x - degree;
            this.longitudeRadians = PI * (degree + 5 * min / 3d) / 180d;
        } else {
            this.latitudeRadians = Math.toRadians(this.y);
            this.longitudeRadians = Math.toRadians(this.x);
        }


/**
 * Calculates the distance between two points.
 *
 * @param location other Location
 * @return distance
 */
static double EARTH_RADIUS_KM = 6378.388;
private double distance_GEO(Location location) {
    if (USE_TSPLIB_CALC) {
        // https://www.iwr.uni-heidelberg.de/groups/comopt/software/TSPLIB95/tsp95.pdf
        double q1 = cos(longitudeRadians - location.longitudeRadians);
        double q2 = cos(latitudeRadians - location.latitudeRadians);
        double q3 = cos(latitudeRadians + location.latitudeRadians);
        double distance = (int) (EARTH_RADIUS_KM * acos(0.5 * ((1.0 + q1) * q2 - (1.0 - q1) * q3)) + 1.0);
        return distance;
    } else {
        // https://www.movable-type.co.uk/scripts/latlong.html
        // https://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates
        double dLat = Math.toRadians(y - location.y);
        double dLon = Math.toRadians(x - location.x);

        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(latitudeRadians) * Math.cos(location.latitudeRadians);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return EARTH_RADIUS_KM * c;
    }
}