分支定界法开始看的时候还是很难能通俗易懂地描述出该算法的规则和界限。顾名思义就是按名字来划分,分支可看作一个二叉树,而定界就可理解为对上述二叉树的一种约束。
具体可以参考该连接的描述:只需要看两张图片即可,如何将图转化为一颗树
还有另外一种用法是:一个箱子可装10斤重的货物,其中有三件分别中4 8 5斤可不拆分的货物,请问最多可装几斤的问题。等等可用此算法的应用。
鄙人实现的是TSP问题,模型构建、解决方案、算法实现等。话不多说上源码。
1.分支定界法的实体bean
import java.io.Serializable;
import java.util.List;
/**
* 分支定界法的实体bean 假设来回的差旅费用不一样
* 实体包含:城市节点编号、城市节点名称、城市节点所属层级、到达城市节点编号、到达城市节点所需费用
*/
public class BranchBound implements Serializable {
// 城市节点编号
private String nodeNo;
// 城市节点名称
private String nodeName;
// 城市节点所属层级
private Integer nodeLevel;
// 到达城市节点编号
private String arrayNodeNo;
// 到达城市节点所需费用
private Double arrayNodeFee;
// 剩余没去的城市节点,节点编号
private List<String> restNodes;
public BranchBound(String nodeNo, String nodeName, String arrayNodeNo, Double arrayNodeFee) {
super();
this.nodeNo = nodeNo;
this.nodeName = nodeName;
this.arrayNodeNo = arrayNodeNo;
this.arrayNodeFee = arrayNodeFee;
}
public String getNodeNo() {
return nodeNo;
}
public void setNodeNo(String nodeNo) {
this.nodeNo = nodeNo;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public Integer getNodeLevel() {
return nodeLevel;
}
public void setNodeLevel(Integer nodeLevel) {
this.nodeLevel = nodeLevel;
}
public String getArrayNodeNo() {
return arrayNodeNo;
}
public void setArrayNodeNo(String arrayNodeNo) {
this.arrayNodeNo = arrayNodeNo;
}
public Double getArrayNodeFee() {
return arrayNodeFee;
}
public void setArrayNodeFee(Double arrayNodeFee) {
this.arrayNodeFee = arrayNodeFee;
}
public List<String> getRestNodes() {
return restNodes;
}
public void setRestNodes(List<String> restNodes) {
this.restNodes = restNodes;
}
}
2.分支界定法的MAP集合
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* 构建分支界定法的MAP集合、该算法的难点不在于算法的本身,而在于如何构建完美二叉树和定界的问题
* 如果城市之间的费用相差不多,那么将会导致该算法变为穷举法,每个分支都将会算到
* 1.定义城市节点的总数量
* 2.初始化城市节点信息以及所需的差旅费、剩余可用城市节点
* 3.获取节点最少费用的上限值(求取思路:计算出所有节点的出边和入边最小的值,而后依据该城市节点总数量*2的边,进行扩展最终求出N*2条线,比较得出最少路径值)
*/
public class BranchBoundMap {
// 城市数量
private Integer nodeCount = 8;
// 城市节点的集合
private List<BranchBound> bbList = new ArrayList<>();
// 存储所有出边和入边的最优路径
private List<BranchBound> bestList = new ArrayList<>();
// 剩余城市节点的集合,节点编号
private List<String> restNodes = new ArrayList<>();
public BranchBoundMap(){
// 初始化剩余可用城市节点
for (int i = 1; i <= nodeCount; i++){