【问题标题】:Solving the Traveling Salesman Problem with bruteforce用蛮力解决旅行推销员问题
【发布时间】:2019-09-04 16:34:24
【问题描述】:

对于一个学校项目,我正在尝试对旅行商问题实施蛮力算法。我想做的是,我输入一个代表点数的整数,对于每个点,都会给出一个随机的 x 和 y 值,代表它们在 2D 平面上的位置。在所有点都被初始化后,算法将从点1开始计算每条路线的距离,然后排列所有不同的可能性。

更新 1:

所以我编写了 Point.java 和 PointManager.java 类,目的是初始化点并将它们保存在数组列表中。 他们看起来像这样 Point.java:

public class Point {

    int x;
    int y;

    //Constructs a random Point
    public Point(){
        this.x = (int)(Math.random()*200);
        this.y = (int)(Math.random()*200);
    }

    //gives Point X Position
    public int getPosX(){
        return this.x;
    }

    //gives Point Y Position
    public int getPosY(){
        return this.y;
    }

    public double distance(Point point){
        int distance_x = Math.abs(getPosX() - point.getPosX());
        int distance_y = Math.abs(getPosY() - point.getPosY());
        double distance = Math.sqrt((distance_x * distance_x) + (distance_y * distance_y));
        return distance;
    }  
}

PointManager.java

import java.util.ArrayList;
public class PointManager {

    // Holds our cities
    private static ArrayList destinationPoints = new ArrayList<Point>();

    // Adds a destination city
    public static void addPoint(Point point) {
        destinationPoints.add(point);
    }

    // Get a city
    public static Point getPoint(int index){
        return (Point)destinationPoints.get(index);
    }

    // Get the number of destination cities
    public static int numberOfPoints(){
        return destinationPoints.size();
    } 
}

现在我的问题是,我将如何继续进行可能性的不同排列以及如何检查某个点是否已在路线中使用?

【问题讨论】:

  • 那么你的问题是什么?
  • 您好,欢迎来到 Stack Overflow。 Stack Overflow 是一个问答平台。你有什么问题?
  • 虽然我投票支持重新提出这个问题,但我强烈建议您至少提出一些您的方法,并指出它有什么问题
  • 是的,我目前正在做的事情,这意味着一开始的一些一般建议,当我遇到问题或需要建议时。顺便说一句,这是我第一次使用 stackoverflow,所以我不知道这是否允许。当我取得进展时,我会保持更新
  • 除非你必须编写自己的 Point,否则我建议使用内置类型。重新发明轮子是没有意义的。

标签: java arrays algorithm arraylist


【解决方案1】:

最直接的解决方案是使用递归:

它跟踪哪些点已被访问,哪些仍需要访问。 在每次调用时,它只是用所有可能的“下一个点”扩展当前路径。

当没有更多点要包含时,它会打印路径。

private static void branch(Set<Point> todoPoints, List<Point> donePoints){
    if(todoPoints.isEmpty()){
        // measure distance
        double totalDistance = 0;
        for (int i = 0; i < donePoints.size(); i++) {
            totalDistance += donePoints.get(i).distance(donePoints.get((i+1) % donePoints.size()));
        }
        System.out.println("Solution found");
        System.out.println("\t" + donePoints);
        System.out.println("\t"+totalDistance);
    }else{
        for(Point nextPoint : todoPoints){
            // add point
            donePoints.add(nextPoint);

            // recurse
            Set<Point> tmp = new HashSet<>(todoPoints);
            tmp.remove(nextPoint);
            branch(tmp, donePoints);

            // remove point
            donePoints.remove(nextPoint);
        }
    }
}

当然,这个策略可以改进。 我们可以跟踪当前的最小距离,并使用它。 例如,延长已经超过当前最小距离的路径没有任何附加价值。

看起来像这样:

private static void branch2(Set<Point> todoPoints, List<Point> donePoints, double dist){
    if(todoPoints.isEmpty()){
        dist += donePoints.get(0).distance(donePoints.get(donePoints.size()-1));
        CURRENT_MIN_DIST = java.lang.Math.min(CURRENT_MIN_DIST, dist);
        System.out.println("Solution found");
        System.out.println("\t" + donePoints);
        System.out.println("\t"+dist);
    }else{
        for(Point nextPoint : todoPoints){
            // add point
            donePoints.add(nextPoint);

            // update distance
            dist += (donePoints.size() > 1 ? donePoints.get(donePoints.size()-2).distance(donePoints.get(donePoints.size()-1)) : 0);

            // we do not recurse if the current distance is already bigger than a known minimum
            if(dist > CURRENT_MIN_DIST)
                continue;

            // recurse
            Set<Point> tmp = new HashSet<>(todoPoints);
            tmp.remove(nextPoint);
            branch2(tmp, donePoints, dist);

            // remove point
            donePoints.remove(nextPoint);
        }
    }
}

最后,进一步的改进是跟踪完成当前路径所需添加的最小距离。

然后你可以进一步修剪这个递归。 你可以检查

当前距离+完成所需的最小距离

可以这样实现:

private static void branch3(Set<Point> todoPoints, List<Point> donePoints, double dist){
    if(todoPoints.isEmpty()){
        dist += donePoints.get(0).distance(donePoints.get(donePoints.size()-1));
        CURRENT_MIN_DIST = java.lang.Math.min(CURRENT_MIN_DIST, dist);
        System.out.println("Solution found");
        System.out.println("\t" + donePoints);
        System.out.println("\t"+dist);
    }else{
        for(Point nextPoint : todoPoints){
            // add point
            donePoints.add(nextPoint);

            // update distance
            dist += (donePoints.size() > 1 ? donePoints.get(donePoints.size()-2).distance(donePoints.get(donePoints.size()-1)) : 0);

            // we do not recurse if the current distance is already bigger than a known minimum
            if(dist > CURRENT_MIN_DIST)
                continue;

            if(dist + minDistToFinish(todoPoints) > CURRENT_MIN_DIST)
                continue;

            // recurse
            Set<Point> tmp = new HashSet<>(todoPoints);
            tmp.remove(nextPoint);
            branch3(tmp, donePoints, dist);

            // remove point
            donePoints.remove(nextPoint);
        }
    }
}

相关方法如下所示:

private static double minDistToFinish(Set<Point> todoPoints){
    double distToFinish = 0;
    for(Point p1 : todoPoints){
        double d = Double.MAX_VALUE;
        for(Point p2 : todoPoints){
            if(p1.equals(p2))
                continue;
            d = java.lang.Math.min(d, p1.distance(p2));
        }
        distToFinish += d;
    }
    return distToFinish;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多