Java中TSP的动态编程方法 [英] Dynamic programming approach to TSP in Java

查看:167
本文介绍了Java中TSP的动态编程方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个初学者,我正在尝试使用动态编程方法编写一个行进的旅行推销员问题。

I'm a beginner, and I'm trying to write a working travelling salesman problem using dynamic programming approach.

这是我的计算函数的代码:

This is the code for my compute function:

public static int compute(int[] unvisitedSet, int dest) {
    if (unvisitedSet.length == 1)
        return distMtx[dest][unvisitedSet[0]];

    int[] newSet = new int[unvisitedSet.length-1];
    int distMin = Integer.MAX_VALUE;

    for (int i = 0; i < unvisitedSet.length; i++) {

        for (int j = 0; j < newSet.length; j++) {
            if (j < i)          newSet[j] = unvisitedSet[j];
            else                newSet[j] = unvisitedSet[j+1];
        }

        int distCur;

        if (distMtx[dest][unvisitedSet[i]] != -1) {
            distCur = compute(newSet, unvisitedSet[i]) + distMtx[unvisitedSet[i]][dest];

            if (distMin > distCur)
                distMin = distCur;
        }
        else {
            System.out.println("No path between " + dest + " and " + unvisitedSet[i]);
        }
    }
    return distMin;
}

代码没有给我正确的答案,我正在尝试找出发生错误的位置。我认为添加以下内容时会发生我的错误:
distCur = compute(newSet,unvisitedSet [i])+ distMtx [unvisitedSet [i]] [dest];
所以我一直在弄乱那部分,在我返回 distMin 之前将加法移到最后,依此类推……但是我不能找出答案。

The code is not giving me the correct answers, and I'm trying to figure out where the error is occurring. I think my error occurs when I add: distCur = compute(newSet, unvisitedSet[i]) + distMtx[unvisitedSet[i]][dest]; So I've been messing around with that part, moving the addition to the very end right before I return distMin and so on... But I couldn't figure it out.

尽管我确定可以从代码中推断出这一点,但我将陈述以下事实加以澄清。

Although I'm sure it can be inferred from the code, I will state the following facts to clarify.

distMtx 存储所有城际距离,并且距离是对称的,这意味着如果从城市A到城市B的距离为3,则从城市B到城市B的距离城市A也是3。此外,如果两个城市没有任何直接路径,则距离值为-1。

distMtx stores all the intercity distances, and distances are symmetric, meaning if distance from city A to city B is 3, then the distance from city B to city A is also 3. Also, if two cities don't have any direct paths, the distance value is -1.

任何帮助将不胜感激!
谢谢!

Any help would be very much appreciated! Thanks!

编辑:

主要功能是从文本文件读取城际距离。因为我假设城市数量总是少于100,所以全局整数变量 distMtx 是[100] [100]。

The main function reads the intercity distances from a text file. Because I'm assuming the number of cities will always be less than 100, global int variable distMtx is [100][100].

一旦矩阵中填充了必要的信息,就会创建一个包含所有城市的数组。城市的名称基本上是数字。因此,如果我有4个城市,则 set [4] = {0,1,2,3}

Once the matrix is filled with the necessary information, an array of all the cities are created. The names of the cities are basically numbers. So if I have 4 cities, set[4] = {0, 1, 2, 3}.

在主函数中,创建 distMtx set 之后,首先调用 compute() 称为:

In the main function, after distMtx and set is created, first call to compute() is called:

int optRoute = compute(set, 0);
System.out.println(optRoute);

样本输入:

-1 3 2 7
3 -1 10 1
2 10 -1 4
7 1 4 -1

预期输出:

10


推荐答案

这是使用动态编程对TSP进行迭代的可行解决方案。使您的生活更轻松的是将当前状态存储为位掩码,而不是存储在数组中。这具有状态表示形式紧凑且可以轻松缓存的优点。

Here's a working iterative solution to the TSP with dynamic programming. What would make your life easier is to store the current state as a bitmask instead of in an array. This has the advantage that the state representation is compact and can be cached easily.

我制作了视频详细介绍了YouTube上此问题的解决方案,请尽情享受!代码来自我的 github存储库

I made a video detailing the solution to this problem on Youtube, please enjoy! Code was taken from my github repo

/**
 * An implementation of the traveling salesman problem in Java using dynamic 
 * programming to improve the time complexity from O(n!) to O(n^2 * 2^n).
 *
 * Time Complexity: O(n^2 * 2^n)
 * Space Complexity: O(n * 2^n)
 *
 **/

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class TspDynamicProgrammingIterative {

  private final int N, start;
  private final double[][] distance;
  private List<Integer> tour = new ArrayList<>();
  private double minTourCost = Double.POSITIVE_INFINITY;
  private boolean ranSolver = false;

  public TspDynamicProgrammingIterative(double[][] distance) {
    this(0, distance);
  } 

  public TspDynamicProgrammingIterative(int start, double[][] distance) {
    N = distance.length;

    if (N <= 2) throw new IllegalStateException("N <= 2 not yet supported.");
    if (N != distance[0].length) throw new IllegalStateException("Matrix must be square (n x n)");
    if (start < 0 || start >= N) throw new IllegalArgumentException("Invalid start node.");

    this.start = start;
    this.distance = distance;
  }

  // Returns the optimal tour for the traveling salesman problem.
  public List<Integer> getTour() {
    if (!ranSolver) solve();
    return tour;
  }

  // Returns the minimal tour cost.
  public double getTourCost() {
    if (!ranSolver) solve();
    return minTourCost;
  }

  // Solves the traveling salesman problem and caches solution.
  public void solve() {

    if (ranSolver) return;

    final int END_STATE = (1 << N) - 1;
    Double[][] memo = new Double[N][1 << N];

    // Add all outgoing edges from the starting node to memo table.
    for (int end = 0; end < N; end++) {
      if (end == start) continue;
      memo[end][(1 << start) | (1 << end)] = distance[start][end];
    }

    for (int r = 3; r <= N; r++) {
      for (int subset : combinations(r, N)) {
        if (notIn(start, subset)) continue;
        for (int next = 0; next < N; next++) {
          if (next == start || notIn(next, subset)) continue;
          int subsetWithoutNext = subset ^ (1 << next);
          double minDist = Double.POSITIVE_INFINITY;
          for (int end = 0; end < N; end++) {
            if (end == start || end == next || notIn(end, subset)) continue;
            double newDistance = memo[end][subsetWithoutNext] + distance[end][next];
            if (newDistance < minDist) {
              minDist = newDistance;
            }
          }
          memo[next][subset] = minDist;
        }
      }
    }

    // Connect tour back to starting node and minimize cost.
    for (int i = 0; i < N; i++) {
      if (i == start) continue;
      double tourCost = memo[i][END_STATE] + distance[i][start];
      if (tourCost < minTourCost) {
        minTourCost = tourCost;
      }
    }

    int lastIndex = start;
    int state = END_STATE;
    tour.add(start);

    // Reconstruct TSP path from memo table.
    for (int i = 1; i < N; i++) {

      int index = -1;
      for (int j = 0; j < N; j++) {
        if (j == start || notIn(j, state)) continue;
        if (index == -1) index = j;
        double prevDist = memo[index][state] + distance[index][lastIndex];
        double newDist  = memo[j][state] + distance[j][lastIndex];
        if (newDist < prevDist) {
          index = j;
        }
      }

      tour.add(index);
      state = state ^ (1 << index);
      lastIndex = index;
    }

    tour.add(start);
    Collections.reverse(tour);

    ranSolver = true;
  }

  private static boolean notIn(int elem, int subset) {
    return ((1 << elem) & subset) == 0;
  }

  // This method generates all bit sets of size n where r bits 
  // are set to one. The result is returned as a list of integer masks.
  public static List<Integer> combinations(int r, int n) {
    List<Integer> subsets = new ArrayList<>();
    combinations(0, 0, r, n, subsets);
    return subsets;
  }

  // To find all the combinations of size r we need to recurse until we have
  // selected r elements (aka r = 0), otherwise if r != 0 then we still need to select
  // an element which is found after the position of our last selected element
  private static void combinations(int set, int at, int r, int n, List<Integer> subsets) {

    // Return early if there are more elements left to select than what is available.
    int elementsLeftToPick = n - at;
    if (elementsLeftToPick < r) return;

    // We selected 'r' elements so we found a valid subset!
    if (r == 0) {
      subsets.add(set);
    } else {
      for (int i = at; i < n; i++) {
        // Try including this element
        set |= 1 << i;

        combinations(set, i + 1, r - 1, n, subsets);

        // Backtrack and try the instance where we did not include this element
        set &= ~(1 << i);
      }
    }
  }

  public static void main(String[] args) {
    // Create adjacency matrix
    int n = 6;
    double[][] distanceMatrix = new double[n][n];
    for (double[] row : distanceMatrix) java.util.Arrays.fill(row, 10000);
    distanceMatrix[5][0] = 10;
    distanceMatrix[1][5] = 12;
    distanceMatrix[4][1] = 2;
    distanceMatrix[2][4] = 4;
    distanceMatrix[3][2] = 6;
    distanceMatrix[0][3] = 8;

    int startNode = 0;
    TspDynamicProgrammingIterative solver = new TspDynamicProgrammingIterative(startNode, distanceMatrix);

    // Prints: [0, 3, 2, 4, 1, 5, 0]
    System.out.println("Tour: " + solver.getTour());

    // Print: 42.0
    System.out.println("Tour cost: " + solver.getTourCost());
  }
}

这篇关于Java中TSP的动态编程方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆