tsp 分支界限 java_TSP问题(旅行商问题)[分支限界法]

问题:

旅行商从 a 开始周游下图所有的城市一次,然后回到 a,城市之间的旅行代价在图中标明。

请选择一个最优的行走顺序使得周游所有城市的代价最小。

4567a1a11459e67b0347ba08a36c1ab5.png

思路:

随便怎么周游,对于一个城市来说,一定有一条进的路和一条出的路。

对于每个城市来说,暂时都选取代价最小的两条路来作为理想的路线,就算这些路不合理。

比如对于 a 来说,选择 ac(1) & ab(3) ;对于 e 来说,选择 ec(2) & ed(3)。

把所有的这些值加起来除以2,

本题即 lb=[(ac+ab)+(ba+bc)+(ca+ce)+(de+dc)+(ec+ed)]/2=[(1+3)+(3+6)+(1+2)+(3+4)+(2+3)]/2=14 .

把这个值当成是理想的最小代价,然后接下来搜索解空间树的时候,都在该基础上进行。

下面画出搜索解空间树的过程,其中方框上面的是点的名称,下面是假设的理想周游代价,方框头顶是搜索顺序:

刚开始从 a 走

dc92880493da826d0dcf30d1f2bca082.png

从 a 可以到达 b、c、d、e,

4adb595c4281ea70a8eefe43e2eb305d.png

这里有一个小细节,就是图中的 2 节点。想想如果周游路线 abdea 和 aedcba ,这两条路线其实是一样的,但是如果不加处理的话,可能两条路线会在搜索的时候都被搜索过,这样浪费了时间。因此,我们这里做个小约定,约定 b 要在 c 之前出现。因此,图中节点 2 就被抛弃了。

继续上面的,从 a 走到那些点后,怎么计算理想代价呢,也就是说怎么计算 lb 呢。

我们用 a 到 d 来举例子吧。

最开始 lb 是选取每个点的代价最小的两条路, lb=[(ac+ab)+(ba+bc)+(ca+ce)+(de+dc)+(ec+ed)]/2。a 走的是c 和 b 这两个,d 走的是e 和 c 。

现在我们选择 ad ,那 d 的一条路要被改成 a 了。我们选择将原来的 ab 改成 ad,因为要使代价最小,所以选择代价大的来替换。那么 dc 就被替换成 da了。这时再计算就可以得到新的 lb 了。

我们应该选择 lb 最小的往下搜索,较大的等下再搜索。于是

53350994b06835a2b26406a1b8f54310.png

继续向下

41e97d31cdee4de821f29ab06e39d980.png

这时已经找出两个周游路程了(因为最后肯定要回到 a 就没向下画了),我们继续搜索,看看有没再好点的解。向上退一层,就是 节点 6 了,所以

76afb5624db0ff261989797d040a4e8c.png

继续搜索,发现节点 7 才走到 e 就要 19,而 节点 11 走完了只需要 16,所以把它抛弃,继续退回,发现 3,4 都不行

7da09298029a07cfba4ca2d0288b2fa5.png

得到了最优解。

代码:

代码我不会写,哈哈哈哈哈哈哈哈哈。。。。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旅行商问题是一个经典的组合优化问题,其目标是寻找一条路径,使得经过所有城市且回到起点的总距离最短。而分支限界法是一种常用的求解组合优化问题的算法,它通过不断分支扩展搜索树来逐步缩小问题的解空间。下面我们来看一下如何使用分支限界法来解决旅行商问题。 首先,我们需要定义一个节点类来表示每个搜索树节点。节点类包含以下成员变量: - path:当前路径 - bound:当前路径的下界 - level:搜索树的深度 其中,path表示当前已经走过的路径,bound表示当前路径的下界(即从当前节点到终点的最小估计距离),level表示搜索树的深度。 接下来,我们需要编写一个优先队列来存储搜索树节点,并按照下界从小到大排序。每次取出队首节点进行扩展,直到找到最优解为止。扩展节点时,我们需要根据当前路径计算下界,并根据下界更新优先队列。 具体来说,我们可以按照以下步骤进行搜索: 1. 初始化优先队列,并将根节点加入队列中。 2. 取出队首节点进行扩展,如果当前路径已经经过所有城市,则更新最优解并返回。 3. 根据当前路径计算下界,并根据下界更新优先队列。 4. 对队列中的节点按照下界排序,并重复步骤2-3,直到找到最优解为止。 在计算下界时,我们可以采用一些启发式算法来估计从当前节点到终点的最小距离。常用的启发式算法包括最小生成树算法和最近邻算法等。具体的实现细节可以根据具体情况进行调整。 下面是一个简单的Java实现,仅供参考: ```java class Node implements Comparable<Node> { int[] path; // 当前路径 int bound; // 当前路径的下界 int level; // 搜索树的深度 public Node(int[] path, int bound, int level) { this.path = path; this.bound = bound; this.level = level; } public int compareTo(Node other) { return this.bound - other.bound; } } public class TSP { private int n; // 城市个数 private int[][] graph; // 城市间距离矩阵 private int[] bestPath; // 最优路径 private int bestDist = Integer.MAX_VALUE; // 最优路径长度 public TSP(int n, int[][] graph) { this.n = n; this.graph = graph; this.bestPath = new int[n]; } public void solve() { PriorityQueue<Node> queue = new PriorityQueue<>(); int[] path = new int[n]; int bound = getBound(path, 0); queue.offer(new Node(path, bound, 0)); while (!queue.isEmpty()) { Node node = queue.poll(); int[] curPath = node.path; int curBound = node.bound; int level = node.level; if (level == n) { int dist = getDist(curPath); if (dist < bestDist) { bestDist = dist; System.arraycopy(curPath, 0, bestPath, 0, n); } continue; } for (int i = level; i < n; i++) { swap(curPath, i, level); int newBound = curBound - graph[curPath[level - 1]][curPath[level]] + graph[curPath[level - 1]][curPath[level + 1]] + getBound(curPath, level + 1); if (newBound < bestDist) { int[] newPath = Arrays.copyOf(curPath, n); queue.offer(new Node(newPath, newBound, level + 1)); } swap(curPath, i, level); } } } private int getBound(int[] path, int level) { int bound = 0; boolean[] visited = new boolean[n]; for (int i = 0; i < level; i++) { visited[path[i]] = true; bound += graph[path[i]][path[i + 1]]; } bound += getMST(visited); return bound; } private int getMST(boolean[] visited) { int[] dist = new int[n]; Arrays.fill(dist, Integer.MAX_VALUE); dist[0] = 0; int weight = 0; for (int i = 0; i < n; i++) { int u = -1; for (int j = 0; j < n; j++) { if (!visited[j] && (u == -1 || dist[j] < dist[u])) { u = j; } } visited[u] = true; weight += dist[u]; for (int j = 0; j < n; j++) { if (!visited[j] && graph[u][j] < dist[j]) { dist[j] = graph[u][j]; } } } return weight; } private int getDist(int[] path) { int dist = 0; for (int i = 0; i < n; i++) { dist += graph[path[i]][path[i + 1]]; } return dist; } private void swap(int[] path, int i, int j) { int temp = path[i]; path[i] = path[j]; path[j] = temp; } } ``` 以上就是使用分支限界法解决旅行商问题的基本思路和实现方法。需要注意的是,旅行商问题是一个NP-hard问题,因此在实际应用中,算法的时间复杂度和空间复杂度往往会非常高,需要根据具体情况进行优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值