Branch and Bound(分支定界算法)学习笔记

分支定界算法的基本介绍:分支定界算法作为在解决整数规划问题的精确算法中最基本、最底层的算法,由伦敦政治经济学院的 Ailsa Land 和 Alison Doig 于1960年首次提出,是一种分而治之、先松后紧、张弛有度的算法。而后在1963年,由 John D.C. Little 在发表的关于TSP的研究中,明确使用“Branch and Bound“ 对该方法进行命名。

分支定界算法的一般步骤和主要特征梳理如下:

(1)松弛:线性松弛,将整数规划(IP)松弛为对应的整数规划线性松弛(IPr);

(2)分支:通过不断分支,将初始IPr的可行域连续划分为多个子区域;

(3)求解:求解每个子区域对应的子问题;

(4)更新:根据子问题的最优值、解的整数特性、目标函数的优化方向,来更新全局上下界

(5)终止:获得最优解,或上下界在一定容差界限内。

线性松弛

定义:将整数规划(IP)的整数约束和0-1约束全部去掉,会得到一个线性规划(LP),该线性规划(LP)被称为原来整数规划的线性松弛,本文用符号(IPr)来表示(IP)的线性松弛问题。

分支定界树

这一个不断二分的树形结构,也经常被称为分支定界树,Branch-and-Bound Tree(BB tree)

BB tree的一些重要的概念和特征:

(1)BB tree的根节点,无前驱节点,相当于IP对应的线性松弛问题IPr

(2)BB tree是满二叉树结构树中的节点要么是出度为2的节点,要么是叶子节点,出度为0,不存在出度为其他值的节点,相当于对于树中节点对应的任何一个问题,要么能分为两个子问题,要么不可再分;

(3)BB tree子节点的度等于2,其后有2个后继节点,相当于将当前问题分为两个可行域无交集的子问题

(4)BB tree叶子节点的度等于0,其后有0个后继节点,当前节点已被剪枝,相当于当前问题已被查明/洞悉,不会再分;

(5)BB tree节点的查明/洞悉,被查明的节点无需再分支,我们可以将其进行剪枝,若节点对应的问题满足下面的任何一个条件,则可判断该节点已被查明;

  • 该节点不可行。即可行性剪枝,节点对应的问题无意义

  • 该节点得到了一个整数解。即最优性剪枝,节点对应的问题已经完成了使命

  • 该节点的线性松弛问题的最优值,不超过全局下界(最大化问题)。即界限剪枝,节点松弛之后求得的解,还没有目前的全局下界高,可以预见到继续分支不会对问题全局下界有任何影响,无分支的必要了

 (6)BB tree的终止条件,当所有的叶子节点均被查明,或全局上下界的在所给的容差界限内。

分支定界算法解析

分支定界算法始终围绕着一颗搜索树进行的,我们将原问题看作搜索树的根节点,从这里出发,分支的含义就是将大的问题分割成小的问题。

分支的过程就是不断给树增加子节点的过程。而定界就是在分支的过程中检查子问题的上下界,如果子问题不能产生一比当前最优解还要优的解,那么砍掉这一支。直到所有子问题都不能产生一个更优的解时,算法结束

最大化问题的分支定界算法伪代码如下所示:

 最大化问题的分支定界算法流程图:

 分支、搜索与剪枝策略

在实际的操作过程中,仍有一些内容需要关注,主要包括分支、搜索与剪枝策略三部分,对于这几部分的设计与选择会直接影响算法的求解效率

(1)分支策略

在选取分支变量对父节点的问题进行分支时,可能存在若干个非整数变量,那么如何选择具体的分支变量,下面给出了几种常见的可选分支策略:

  • 最不可行分支:选择分数部分最接近0.5的(最偏离整数的)变量进行分支;

  • 最大分数值分支:选择分数部分最大的变量进行分支;

  • 伪检验数分支:在使用启发式方法近似估计约束对偶变量的基础上,得到变量检验数的估计值,进一步评估变量的分支对目标函数的影响,最终选择更有利的分支变量;

  • 强分支:在分之前首先估计哪个分支会给目标函数带来最大改进,然后选择该变量进行分支。

(2)搜索策略

在节点队列中,对于不同子节点的选择会直接影响BB tree的搜索策略,一些常见的遍历策略如下所示。

  • 深度优先搜索:在发生剪枝前,下一次搜索的节点一定是当前节点的后继,节点队列“先入后出”一般可保证深优;

  • 广度优先搜索:优先遍历同一层次的节点,完毕后再遍历下一层次的节点,节点队列“先入先出”一般可保证宽优;

  • 最好界限优先搜索:根据问题的优化方向,选择局部LB或者局部UB最好的节点首先被搜索。

(3)剪枝策略

  • 查明一个节点:包含前述的3个查明条件(可行、最优、界限)之一,即可进行剪枝;

  • 优超关系:更加灵活和动态的一种“界限剪枝”,如果基于一些信息,在任何时候都可以确定节点y的最佳子节点至少与节点x的最佳子节点一样好,那么就说y优超了x,那么x就失去了搜索的必要,将其剪枝。

案例分析一:利用分支定界算法求解最大化优化问题

代码逻辑描述:

1.求解线性松弛的原问题,判断是否可行

2.当未被探索的问题集不为空,且上下界的gap大于阈值,则根据搜索策略选择子问题进行探索

3.算法的终止条件 当未被探索的问题集不为空;如果上界等于下界,或者上界-下界的gap很小,则算法终止。

from gurobipy import *
import copy
import numpy as np
import matplotlib.pyplot as plt

RLP = Model("relaxed IP")
x = {}

# 设置决策变量
for i in range(2):
    x[i] = RLP.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name = 'x_'+str(i))

# 设置目标函数和约束条件
RLP.setObjective(100*x[0]+150*x[1],GRB.MAXIMIZE)
RLP.addConstr(2*x[0]+x[1]<=10)
RLP.addConstr(3*x[0]+6*x[1]<=40)

# 求解解松弛问题
RLP.optimize()

class Node:
    def __init__(self):
        self.model = None
        self.x_sol = {} #solution of sub-problem
        self.x_int_sol = {} #round integer of solution
        self.local_LB = 0  #local bound of node, sub-problem
        self.local_UB = np.inf
        self.is_integer = False #is integr solution
        self.branch_var_list = []  #store branch variable

    def deepcopy(node):
        new_node = Node()
        new_node.local_LB = 0
        new_node.local_UB = np.inf
        new_node.x_sol = copy.deepcopy(node.x_sol) #solution of sub-problem
        new_node.x_int_sol = copy.deepcopy(node.x_int_sol) #round integer of solution
        new_node.branch_var_list = [] # do not copy, or that always use the same branch_var_list in sub-problem
        # deepcopy, or that the subproblem add all the new constraints sub-problem->infeasible
        new_node.model = node.model.copy()  # gurobi can deepcopy model
        new_node.is_integer = node.is_integer

        return new_node

def branch_and_bound(RLP):
    # initialize the initial node
    RLP.optimize()
    global_UB = RLP.ObjVal
    global_LB = 0
    eps = 1e-3
    incumbent_node = None
    Gap = np.inf

    '''
        branch and bound
    '''

    # create initial node
    Queue = []
    node = Node()
    node.local_LB = 0
    node.local_UB = global_UB
    node.model = RLP.copy()
    node.model.setParam("OutputFlag",0)
    node.cnt = 0
    Queue.append(node)

    cnt = 0
    Global_UB_change = []
    Global_LB_change = []
    while(len(Queue) > 0 and global_UB - global_LB > 
### Branch-and-Price Algorithm in Operations Research and Optimization Branch-and-Price is an advanced technique that combines branch-and-bound with column generation methods to solve large-scale integer programming problems effectively. This approach decomposes complex models into smaller subproblems, which are easier to manage and optimize individually before integrating solutions through pricing mechanisms. The core idea behind this methodology involves iteratively generating columns (variables) as needed during the solution process rather than enumerating all possibilities upfront. Such dynamic addition of variables significantly reduces computational burden while maintaining optimality guarantees[^3]. In practice, implementing Branch-and-Price requires careful consideration of several components: 1. **Master Problem**: Formulates constraints based on existing columns. 2. **Subproblem or Pricing Problem**: Identifies new promising columns not yet included in the master problem by evaluating reduced costs associated with potential additions. 3. **Column Generation Process**: Iterates between solving the restricted master problem and identifying additional profitable columns until no further improvement can be made. 4. **Branching Strategy**: Once optimal fractional solutions emerge from column generation phase, branching decisions split feasible regions strategically to enforce integrality conditions progressively towards obtaining final integer-optimal results. ```python def branch_and_price(master_problem, pricing_problem): # Initialize with initial set of columns current_columns = initialize_columns() while True: # Solve Master Problem status, obj_val, duals = solve_master_problem(current_columns) if check_optimality(duals): break # Generate new columns via Subproblem/Pricing Problem new_column = generate_new_column(pricing_problem, duals) if not new_column: break # Add newly generated column(s) back into Master Problem add_to_current_columns(new_column) return get_integer_solution(status, obj_val) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值