分支限界——旅行商问题分析

问题描述

某售货员要到若干城市去推销产品,已知各城市之间的路程(或旅费)。他要选定一个城市出发,经过每个城市一遍,最后回到出发的城市,使总的路程(或旅费)最小。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbTBfNTExMjA5MDM=,size_8,color_FFFFFF,t_70,g_se,x_16

分支限界基本思想

分支限界法常以广度优先或以最小耗费优先的方式搜索问题的解空间树。

分支限界中存在限界函数也是剪枝函数,即当搜索到某一节点发现它的价值以及大于了目前的最优值,那么该节点就没有必要扩展下去,可以剪掉,以提高搜索效率。

广度优先:搜索树的节点过程是从左到右的顺序的

深度优先:搜索树的节点过程是从上到下的顺序的

解空间树:表示问题解空间的一颗有序树,在下面会详细说到。树分为子集树和排列树。

子集树:当所给问题是从n个元素的集合S中找出S满足某种性质的子集时,相应的解空间称为子集树。也就是它的结果中是n个元素的某个子集,不需要包括全部的元素

排列树:当所给问题的确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。它的结果要包括全部元素,只是排列方式不同,例如元素为1,2,3,4;那他的结果都是1,3,2,4或2,3,1,4等等

分支限界的搜索策略

在扩展节点处,先生成其所有的儿子节点(分支),再从当前的活结点表中选择下一个扩展节点。

### 分支限界法解决TSP问题的实现方法 分支限界法是一种通过剪枝来减少搜索空间的方法,适用于组合优化问题。对于旅行商问题(Traveling Salesman Problem, TSP),目标是最小化访问所有城市并回到起点的距离总和。 #### 数据结构设计 为了高效存储和处理中间状态,通常会定义一个 `QNode` 结构体或类,用来保存当前路径的状态以及对应的代价。以下是常见的字段: - **path**: 当前已经经过的城市序列。 - **visited**: 布尔数组,标记哪些城市已经被访问过。 - **cost**: 到目前为止累积的成本。 - **bound**: 上界估计值,用于判断是否继续扩展该节点[^3]。 #### 算法核心逻辑 1. 初始化优先队列,并插入起始节点(仅包含出发城市的节点)。 2. 使用循环不断提取队首元素直到找到完整的解或者队列为空为止。如果某个节点代表了一条完整路线,则记录下来作为候选最佳方案;否则尝试进一步展开它所指向的新位置。 3. 在每次迭代过程中计算新产生的子树根部可能达到的最佳情况——即所谓的“边界”,并与全局最优值对比决定舍弃与否。 #### 关键操作细节 - 构造初始解时需考虑如何快速估算剩余部分最小开销以便设立合理的界限值。一种常见做法是以贪心策略为基础构建近似解答再调整得到更精确的结果。 - 应用广度优先搜索模式配合优先级机制使得能够尽早发现较优的选择从而提前终止不必要的深入探测动作[^3]。 ```java // 定义常量无穷大 final int INF = 0x3f3f3f3f; class QNode { List<Integer> path; boolean[] visited; int cost; int bound; public QNode(List<Integer> p, boolean[] v, int c, int b){ this.path = new ArrayList<>(p); this.visited = Arrays.copyOf(v, v.length); this.cost = c; this.bound = b; } } public class BranchAndBoundTSP { private int[][] distanceMatrix; // 距离矩阵 private PriorityQueue<QNode> pq; public void solve(int nCities){ initPQueue(); // 创建第一个结点 List<Integer> initialPath = new ArrayList<>(); initialPath.add(0); // 假定从第0个城市开始 boolean[] initialVisited = new boolean[nCities]; initialVisited[0] = true; int initialCost = 0; int initialBound = computeBound(initialPath); addNewNode(new QNode(initialPath, initialVisited, initialCost, initialBound)); while (!pq.isEmpty()){ QNode node = extractMin(); if(node.bound >= minTourLength && !node.path.size()==nCities) continue; expandNode(node); } } private void expandNode(QNode parentNode){ int lastCity = parentNode.path.get(parentNode.path.size()-1); for(int nextCity=0 ;nextCity<distanceMatrix.length; ++nextCity ){ if(!parentNode.visited[nextCity]){ updateAndAddChild(lastCity,nextCity ,parentNode ); } } } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值