基于Cplex的分支定界
前言
分支定界算法是求解整数规划的最常用方法之一,它不仅适用于纯整数规划问题,也适用于混合整数规划问题。分支定界的基本思想是将可行区域分解为越来越小的区域,这一过程为分支过程,对于结果劣于当前界的分支,可以将其舍去,这一过程称之为剪枝,而当我们找到结果好于当前界的整数解,则需要更新当前界,这称之为定界。
整数规划
整数规划问题特指某些变量或全部变量为整数的规划问题,本文说的整数规划指整数线性规划。下面我们看一个简单整数规划的例子。
假如不考虑变量是整数,那么我们直接使用单纯形法求解即可,最终得出答案为:
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的分支定界相关推荐
- 5.1 基于分支定界算法的单机调度
原创文章,禁止转载.抄袭或用于报告.交流等学术或商业用途 全文(其它章节内容) https://blog.csdn.net/qq_38757869/article/details/106885769 ...
- 分支定界方法(branch and cut,branch and price的基础)
目录 1.基础版的分支定界算法(假设是min问题) 2.分支定界算法的步骤及其注意事项 2.1 具体的分支定界方法的步骤: 2.2 迭代过程,也就是分支定界方法的核心操作: 2.3 分支策略: 2.4 ...
- 数学建模基础算法Chapter2.1 -- 整数规划(ILP): 分支定界+割平面
Chapter2.1 – 整数规划(ILP) By 进栈需检票 一.前情提要 当题目要求的最优解是整数,例如物件的数量,参与人员的数量等时,就不能继续使用之前的线性规划了(当出现小数的情况),这个时候 ...
- 分支定界算法在中学排课问题中的应用
分支定界算法在中学排课问题中的应用 摘要:在本文中我们主要研究了带约束有教案的中学排课程表问题.首先我们得到了有关该问题的中学课程表必须满足的几个条件,因为该排课程表问题是一个NP难解的问题,因此该问 ...
- 分支定界---branch and bound
分支定界-branch and bound 定义 分支定界算法始终围绕着一颗搜索树进行的,我们将原问题看作搜索树的根节点,从这里出发,分支的含义就是将大的问题分割成小的问题.大问题可以看成是搜索树的父 ...
- 分支定界法上下界_分支定界(Branch-and-Cut)方法的逻辑
对于一个含有m个变量的模型,如果每个变量是连续变量,每个变量的范围无论是[-5,100].[5,500].[0,1]......,都可以作为LP问题在多项式时间内求解. 现在增加一个条件,模型中有n个 ...
- tsp 分支界限 java_干货 | 10分钟教你用branch and bound(分支定界)算法求解TSP旅行商问题...
在此之前,先给大家讲讲最重要的一个点,搜索树的节点定义,节点定义了原问题的solution和子问题的solution.Node节点定义如下: public class Node {private Ar ...
- SLAM Cartographer(17)分支定界闭环检测
SLAM Cartographer(17)分支定界闭环检测 1. 分支定界原理 2. 快速关联扫描匹配器 2.1. FastCorrelativeScanMatcher2D 2.2. Match 2. ...
- matlab分支定界法linprog_序列比对(二十二)——中间字符串分支定界方法中更紧的界...
原创: hxj7 前文介绍了中间字符串的算法和代码,但是使用分支定界策略时所使用的界限是很宽松的.本文给出了一个更紧的界限. 对分支定界法的简单回顾 前文<序列比对(21)中间字符串问题的算法及 ...
最新文章
- 三大主流软件负载均衡器(LVS、Nginx、HAproxy) 与商业SLB比较
- Linux虚拟文件系统(VFS)
- 常用公有云接入——谷歌
- Linux操作系统之简易实现server/client
- 基本linux命令vi,基本linux和vi命令.pdf
- 信息学奥赛C++语言: 计算两个数的最小公倍数
- [C++] GCC multilib
- matlab2c使用c++实现matlab函数系列教程-binopdf函数
- MySQL 中的日期时间类型
- Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 上篇
- visio插入箭头_visio流程图中画箭头
- 稳压二极管的工作原理及稳压二极管使用电路图
- YYUC01——Windows本地环境搭建
- 2023南京航空航天大学计算机考研信息汇总
- 用FastStone Capture录屏如何发声
- java替换特殊字符_Java处理特殊字符替换(正则表达式)
- 【Python学习】制作一个汇率换算程序
- fluent udf dpm 捕集效率
- 只要简单7步就能破解魔方的图文教程!怎样还原魔方?
- 电脑公司GHOST WIN7 装机旗舰版 2013 04
热门文章
- 通过BPE解决OOV问题----Neural machine Translation of Rare Words with Subword Units
- 从零开始的Flutter入门实战(二)
- 教师计算机基础知识培训简报,信息技术能力提升培训简报.doc
- xcode报错:multiple commands produce Code Signing “No account for team” failed to register bundle
- 32.判断日期的合法性(对于8位数的判断)
- 简易扎金花java程序
- java.io.IOException: No such file or directory之linux权限问题
- 为什么越来越多的人选择海外服务器?
- Style Transfer for Anime Sketches with Enhanced Residual U-net and Auxiliary Classifier GAN
- 给一张图片赋以.jpg结尾的网址