我认为分支限界法与回溯法区别:前者模拟到叶子节点得到一个模拟值、选当前深度最优,贪心算法思想;后者不必到叶子节点,会产生剪枝。
分支限界法分配问题:n项工作分配给n个人,使总成本尽可能小,n阶成本矩阵,任何两个元素不在同一列。
public class Assignment {
static int[][] cost = {
{9, 2, 7, 8},//人员a
{6, 4, 3, 7},//人员b
{5, 8, 1, 8},//人员c
{7, 6, 9, 4} //人员d
};
static int bestSoFar = 9 + 7 + 8 + 9; // 取每一行的最大值相加
public static void main(String[] args) {
// 初始化优先队列,备用
PriorityQueue<Node> S = new PriorityQueue<Node>();
// 初始化一个空状态空间树的结点,即根结点
Node root = new Node();
// 计算第一个目标估计值
root.lowerBound = getLowerBound(root);
// 优先队列中加入根结点,然后准备从根结点开始对状态空间树进行深度优先遍历
S.add(root);
while (S.isEmpty() == false) {
Node node;
node = S.remove(); // 贪心策略:取出lowerBound最小的结点
for (Node child : allChildrenOf(node)) { // 对每一个**可扩展**的子结点
if (isACompleteSolution(child)) { // 如果这个子结点已经是叶子结点
bestSoFar = Math.min(bestSoFar, getLowerBound(child)); // 更新best_so_far
} else if (feasible(child)) {
S.add(child); //加入到优先队列中
} else {
// 其他情况,忽略该子结点。
}
}
}
System.out.print("最优解: "+bestSoFar);
}
//得到下界
private static int getLowerBound(Node node) {
int lb = 0;
int col[] = {0,0,0,0};
// 依照node的信息和权值矩阵cost,计算当前结点的目标预估值
if(node.chosen.size() == 0){
lb = 2 + 3 + 1 + 4 ; //如果是根节点
}else{
for(int i = 0 ; i <= 3 ; i++ ){
if(node.chosen.get(i) != null){
lb += node.chosen.get(i) ;
col[i] = 1;
}
}
for(int i = node.depth + 1; i <= 3 ; i++){
int rowMin = 1000 ;
for(int j = 0 ; j <= 3 ; j++){
if(col[j] == 1){//不能重复列
continue;
}
if(rowMin > cost[i][j]){
rowMin = cost[i][j] ;
}
}
lb += rowMin ;
}
}
return lb ;
}
private static Iterable<Node> allChildrenOf(Node node) {
// nodeList是用来返回的可迭代对象,包含参数node的所有**可扩展**子结点
ArrayList<Node> nodeList = new ArrayList<Node>();
// 1. 如果深度太大,没有孩子
if(node.depth == 3){
return nodeList;
}
// 2. 对所有可能的孩子进行遍历
for (int i = 0; i <= 3; i++) {
// 如果孩子是可扩展的(即不做重复的,先前别人做过的工作)
if (extendable(node, i)) {
// 0. 创建孩子结点:注意维护孩子结点的所有内部属性
Node childNode = new Node();
// 1. chosen //不能childNode.chosen = node.chose ,赋值的是引用
childNode.chosen.putAll(node.chosen) ;
childNode.chosen.put(i, cost[node.depth + 1][i]);
// 2. depth
childNode.depth = node.depth + 1 ;
// 3. lowerBound
childNode.lowerBound = getLowerBound(childNode);
nodeList.add(childNode);
}
}
return nodeList;
}
//判断这个节点是不是叶子节点
private static boolean isACompleteSolution(Node n) {
return n.depth == 3;
}
//节点是否可行
private static boolean feasible(Node n) {
if(n.lowerBound < bestSoFar){
return true ;
}
return false;
}
//节点是否可扩展
private static boolean extendable(Node n, int i) {
Set<Integer>keys = n.chosen.keySet();
Iterator<Integer> it = keys.iterator();
while(it.hasNext()){
if( it.next() == i ){
return false ;
}
}
return true ;
}
}
Node:
import java.util.HashMap;
public class Node implements Comparable {
HashMap<Integer, Integer> chosen;
int lowerBound;
int depth;
public Node() {
chosen = new HashMap<Integer,Integer>();
lowerBound = 0;
depth = -1;
}
@Override
public int compareTo(Node o) {
if(this.lowerBound < o.lowerBound){
return -1;
}else if(this.lowerBound == o.lowerBound){
return 0 ;
}else{
return 1 ;
}
}
}