前言

分支定界算法是求解整数规划的最常用方法之一,它不仅适用于纯整数规划问题,也适用于混合整数规划问题。分支定界的基本思想是将可行区域分解为越来越小的区域,这一过程为分支过程,对于结果劣于当前界的分支,可以将其舍去,这一过程称之为剪枝,而当我们找到结果好于当前界的整数解,则需要更新当前界,这称之为定界。

整数规划

整数规划问题特指某些变量或全部变量为整数的规划问题,本文说的整数规划指整数线性规划。下面我们看一个简单整数规划的例子。

假如不考虑变量是整数,那么我们直接使用单纯形法求解即可,最终得出答案为:
x1*=4.8092 x2*=1.8168 z*=355.8779
很明显它不满足整数条件,因此我们需要对结果进行分支定界处理,假设我选择x1进行分支,那么我们能得到两个子模型。
模型B1=原模型+(x1<=4)
模型B2=原模型+(x1>=5)
由于此时尚未找到可行整数解,此时界bound设为负无穷,任何一个整数解都能更新此界。


求解两个子模型发现解任然是非整数解,这时候需要对子模型进一步分支,对模型B1分支可得到两个新模型。
模型B11=模型B1+(x2<=2)
模型B12=模型B1+(x2>=3)
求解B11与B12有:

此时找到第一个整数解,更新界bound=340,模型B12进行剪枝,不再分支,这是因为B12的非整数解差于当前界,则其整数解不可能好于当前界。

同时注意到B2的解为341.9,因此它有可能产生优于当前界的解,需对模型B2再次分支。
模型B21=模型B2+(x2<=1)
模型B22=模型B2+(x2>=2)
求解模型B21与B22有:

子模型B21的解差于当前界,进行剪枝操作。子模型B22无可行解,同样进行剪枝操作。至此,整个分支定界过程完美结束,我们得到了最终的解340。

Cplex自带整数规划求解

Cplex是一款强力的商业求解器,它自带有整数规划功能,只需在建立模型时将变量类型定义为整型即可,其求解非常简单,代码如下。

//==========================调用cplex的整数规划
void cplex_solve(IloEnv env, IloModel model)
{IloNumVarArray var(env);IloRangeArray con(env);var.add(IloNumVar(env, 0, IloInfinity, ILOINT));//整形var.add(IloNumVar(env, 0, IloInfinity, ILOINT));//整形IloObjective obj = IloMaximize(env, 40 * var[0] + 90 * var[1]);con.add(9 * var[0] + 7 * var[1] <= 56);con.add(7 * var[0] + 20 * var[1] <= 70);model.add(obj);model.add(con);IloNumArray val(env);IloCplex cplex(model);cplex.setOut(env.getNullStream());cplex.solve();cplex.getValues(var, val);env.out() << cplex.getObjValue() << endl;env.out() << val << endl;
}


调用函数,求解完成,最终结果与上面手算结果一致。求解结束之后,大家可能不解,既然Cplex中有自带的整数规划求解部分,那我们还有必要费劲去使用Cplex实现分支定界吗?答案是肯定的,非常有必要。我在上一篇博客基于Cplex的列生成技术中介绍了求解大型整数的列生成技术,我们最后得到的结果是需要20.2个原厂卷纸,很明显我们需要对最终的结果再进行分支定界处理,为什么在列生成时我们不定义变量为整型呢,这样多省事啊,不是我们不愿意这么做,而是这样做不可行,列生成只能求解松弛模型,因此我们只能在求解完之后再手动进行分支定界。列生成+分支定界就构成了鼎鼎大名的分支定价,也就是说,只有学会自己手写分支定界,才能掌握更高级的分支定价。

自定义分支定界求解

在上文中给出了分支定界的手算过程,整个过程比较完整,下面给出分支定界的算法实现流程,其中[x]表示x的值向下取整。

在实现分支定界的过程中,推荐使用优先队列,优先求解目标值更好的模型,这样能大大提高剪枝率,加快求解速度,以下是自定义分支定界的代码,流程与伪代码一致,cmp是自定义的结构体,定义了优先队列的优先顺序。

//==========================自定义分支定界
struct cmp
{bool operator()(IloModel& m1, IloModel& m2){double obj1;IloCplex cplex1(m1);cplex1.setOut(m1.getEnv().getNullStream());if (!cplex1.solve())obj1 = -1e8;else obj1 = cplex1.getObjValue();double obj2;IloCplex cplex2(m2);cplex2.setOut(m2.getEnv().getNullStream());if (!cplex2.solve())obj2 = -1e8;else obj2 = cplex2.getObjValue();return obj1 < obj2;}
};void custom_solve(IloEnv env, IloModel model)
{priority_queue<IloModel, vector<IloModel>, cmp>models;double bound = 0;//当前最优解IloNumArray value(env);//当前最优解对应变量值//建立初始模型IloNumVarArray var(env);IloRangeArray con(env);var.add(IloNumVar(env, 0, IloInfinity));//非整形var.add(IloNumVar(env, 0, IloInfinity));//非整形IloObjective obj = IloMaximize(env, 40 * var[0] + 90 * var[1]);con.add(9 * var[0] + 7 * var[1] <= 56);con.add(7 * var[0] + 20 * var[1] <= 70);model.add(obj);model.add(con);//开始分支定界models.push(model);while (!models.empty()){//求解队顶模型IloCplex cplex(models.top());cplex.setOut(env.getNullStream());if (!cplex.solve()) {models.pop();continue;}IloNumArray val(env);cplex.getValues(var, val);//寻找非整数变量int id = -1;for (int i = 0; i < var.getSize(); i++) {if (val[i] != (int)val[i]) {id = i;break;}}//若当前解为整数解则更新界if (id == -1) {if (cplex.getObjValue() > bound) {bound = cplex.getObjValue();value = val;models.pop();}else {models.pop();}}//若当前解为非整数解则分两支else {IloModel m1(env);m1.add(models.top());m1.add(var[id] <= (int)val[id]);models.push(m1);IloModel m2(env);m2.add(models.top());m2.add(var[id] >= (int)val[id] + 1);models.push(m2);models.pop();}}env.out() << value << endl;env.out() << bound << endl;
}


运行结果如上,与Cplex自带的整数规划求解器求解结果一致,整个求解过程是没有问题的。

完整代码

#include<ilcplex/ilocplex.h>
#include<queue>ILOSTLBEGIN/*
*           求解下列整数规划
*           Max 40x1+90x2
*           s.t.9x1+7x2<=56
*               7x1+20x2<=70
*               x1,x2>=0,且为整数
*
*///==========================调用cplex的整数规划
void cplex_solve(IloEnv env, IloModel model)
{IloNumVarArray var(env);IloRangeArray con(env);var.add(IloNumVar(env, 0, IloInfinity, ILOINT));//整形var.add(IloNumVar(env, 0, IloInfinity, ILOINT));//整形IloObjective obj = IloMaximize(env, 40 * var[0] + 90 * var[1]);con.add(9 * var[0] + 7 * var[1] <= 56);con.add(7 * var[0] + 20 * var[1] <= 70);model.add(obj);model.add(con);IloNumArray val(env);IloCplex cplex(model);cplex.setOut(env.getNullStream());cplex.solve();cplex.getValues(var, val);env.out() << val << endl;env.out() << cplex.getObjValue() << endl;
}//==========================自定义分支定界
struct cmp
{bool operator()(IloModel& m1, IloModel& m2){double obj1;IloCplex cplex1(m1);cplex1.setOut(m1.getEnv().getNullStream());if (!cplex1.solve())obj1 = -1e8;else obj1 = cplex1.getObjValue();double obj2;IloCplex cplex2(m2);cplex2.setOut(m2.getEnv().getNullStream());if (!cplex2.solve())obj2 = -1e8;else obj2 = cplex2.getObjValue();return obj1 < obj2;}
};void custom_solve(IloEnv env, IloModel model)
{priority_queue<IloModel, vector<IloModel>, cmp>models;double bound = 0;//当前最优解IloNumArray value(env);//当前最优解对应变量值//建立初始模型IloNumVarArray var(env);IloRangeArray con(env);var.add(IloNumVar(env, 0, IloInfinity));//非整形var.add(IloNumVar(env, 0, IloInfinity));//非整形IloObjective obj = IloMaximize(env, 40 * var[0] + 90 * var[1]);con.add(9 * var[0] + 7 * var[1] <= 56);con.add(7 * var[0] + 20 * var[1] <= 70);model.add(obj);model.add(con);//开始分支定界models.push(model);while (!models.empty()){//求解队顶模型IloCplex cplex(models.top());cplex.setOut(env.getNullStream());if (!cplex.solve()) {models.pop();continue;}IloNumArray val(env);cplex.getValues(var, val);//寻找非整数变量int id = -1;for (int i = 0; i < var.getSize(); i++) {if (val[i] != (int)val[i]) {id = i;break;}}//若当前解为整数解则更新界if (id == -1) {if (cplex.getObjValue() > bound) {bound = cplex.getObjValue();value = val;models.pop();}else {models.pop();}}//若当前解为非整数解则分两支else {IloModel m1(env);m1.add(models.top());m1.add(var[id] <= (int)val[id]);models.push(m1);IloModel m2(env);m2.add(models.top());m2.add(var[id] >= (int)val[id] + 1);models.push(m2);models.pop();}}env.out() << value << endl;env.out() << bound << endl;
}int main()
{//cplex自带的整数规划求解IloEnv cplex_env;IloModel cplex_model(cplex_env);cplex_solve(cplex_env, cplex_model);//自定义分支定界求解IloEnv custom_env;IloModel custom_model(custom_env);custom_solve(custom_env, custom_model);system("pause");
}

总结

本篇博客与上篇博客分别介绍并实现了分支定界与列生成,下一篇博客将介绍分支定界与列生成的结合,即分支定价算法,仍然以切割问题为例。

基于Cplex的分支定界相关推荐

  1. 5.1 基于分支定界算法的单机调度

    原创文章,禁止转载.抄袭或用于报告.交流等学术或商业用途 全文(其它章节内容) https://blog.csdn.net/qq_38757869/article/details/106885769 ...

  2. 分支定界方法(branch and cut,branch and price的基础)

    目录 1.基础版的分支定界算法(假设是min问题) 2.分支定界算法的步骤及其注意事项 2.1 具体的分支定界方法的步骤: 2.2 迭代过程,也就是分支定界方法的核心操作: 2.3 分支策略: 2.4 ...

  3. 数学建模基础算法Chapter2.1 -- 整数规划(ILP): 分支定界+割平面

    Chapter2.1 – 整数规划(ILP) By 进栈需检票 一.前情提要 当题目要求的最优解是整数,例如物件的数量,参与人员的数量等时,就不能继续使用之前的线性规划了(当出现小数的情况),这个时候 ...

  4. 分支定界算法在中学排课问题中的应用

    分支定界算法在中学排课问题中的应用 摘要:在本文中我们主要研究了带约束有教案的中学排课程表问题.首先我们得到了有关该问题的中学课程表必须满足的几个条件,因为该排课程表问题是一个NP难解的问题,因此该问 ...

  5. 分支定界---branch and bound

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

  6. 分支定界法上下界_分支定界(Branch-and-Cut)方法的逻辑

    对于一个含有m个变量的模型,如果每个变量是连续变量,每个变量的范围无论是[-5,100].[5,500].[0,1]......,都可以作为LP问题在多项式时间内求解. 现在增加一个条件,模型中有n个 ...

  7. tsp 分支界限 java_干货 | 10分钟教你用branch and bound(分支定界)算法求解TSP旅行商问题...

    在此之前,先给大家讲讲最重要的一个点,搜索树的节点定义,节点定义了原问题的solution和子问题的solution.Node节点定义如下: public class Node {private Ar ...

  8. SLAM Cartographer(17)分支定界闭环检测

    SLAM Cartographer(17)分支定界闭环检测 1. 分支定界原理 2. 快速关联扫描匹配器 2.1. FastCorrelativeScanMatcher2D 2.2. Match 2. ...

  9. matlab分支定界法linprog_序列比对(二十二)——中间字符串分支定界方法中更紧的界...

    原创: hxj7 前文介绍了中间字符串的算法和代码,但是使用分支定界策略时所使用的界限是很宽松的.本文给出了一个更紧的界限. 对分支定界法的简单回顾 前文<序列比对(21)中间字符串问题的算法及 ...

最新文章

  1. 三大主流软件负载均衡器(LVS、Nginx、HAproxy) 与商业SLB比较
  2. Linux虚拟文件系统(VFS)
  3. 常用公有云接入——谷歌
  4. Linux操作系统之简易实现server/client
  5. 基本linux命令vi,基本linux和vi命令.pdf
  6. 信息学奥赛C++语言: 计算两个数的最小公倍数
  7. [C++] GCC multilib
  8. matlab2c使用c++实现matlab函数系列教程-binopdf函数
  9. MySQL 中的日期时间类型
  10. Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 上篇
  11. visio插入箭头_visio流程图中画箭头
  12. 稳压二极管的工作原理及稳压二极管使用电路图
  13. YYUC01——Windows本地环境搭建
  14. 2023南京航空航天大学计算机考研信息汇总
  15. 用FastStone Capture录屏如何发声
  16. java替换特殊字符_Java处理特殊字符替换(正则表达式)
  17. 【Python学习】制作一个汇率换算程序
  18. fluent udf dpm 捕集效率
  19. 只要简单7步就能破解魔方的图文教程!怎样还原魔方?
  20. 电脑公司GHOST WIN7 装机旗舰版 2013 04

热门文章

  1. 通过BPE解决OOV问题----Neural machine Translation of Rare Words with Subword Units
  2. 从零开始的Flutter入门实战(二)
  3. 教师计算机基础知识培训简报,信息技术能力提升培训简报.doc
  4. xcode报错:multiple commands produce Code Signing “No account for team” failed to register bundle
  5. 32.判断日期的合法性(对于8位数的判断)
  6. 简易扎金花java程序
  7. java.io.IOException: No such file or directory之linux权限问题
  8. 为什么越来越多的人选择海外服务器?
  9. Style Transfer for Anime Sketches with Enhanced Residual U-net and Auxiliary Classifier GAN
  10. 给一张图片赋以.jpg结尾的网址