是一种在问题的解空间树上搜索问题的解的方法。但与回溯算法不同,分支定界算法采用广度优先或最小耗费优先的方法搜索解空间树,并且,在分支定界算法中,每一个活结点只有一次机会成为扩展结点。
除少数整数规划可以用线性规划的单纯形法直接求解外,一般整数规划必需寻找新的求解方法。这里我们介绍全整数规划的分枝定界方法,它也可以用于求解混合整数规划问题和0-1规划问题。下面我们从一个例子出发来讨论它的思路和步骤。
例1 解下面的整数规划问题
解ILP1的松弛问题ILP1得到
( x 1 , x 2 ) = ( 3 , 3 ) , z m a x = 39 (x_1, x_2)=(3, 3), z_{max} = 39 (x1,x2)=(3,3),zmax=39
解ILP2的松弛问题ILP2得到
( x 1 , x 2 ) = ( 1.8 , 4 ) , z m a x = 41 (x_1, x_2)=(1.8, 4), z_{max} = 41 (x1,x2)=(1.8,4),zmax=41
(3)修改上下界:从LP1和LP2的解我们知道有 39 ≤ z ∗ ≤ 41 39\leq z^*\leq 41 39≤z∗≤41
(4)再分枝:
下面我们就是要划掉LP2的解中 x 1 x_1 x1的小数部分,增加约束 x 1 ≤ 1 x_1\leq 1 x1≤1和 x 1 ≥ 2 x_1\geq 2 x1≥2对ILP2进一步的分枝,即
m a x z = 5 x 1 + 8 x 2 { 5 x 1 + 9 x 2 ≤ 45 x 1 + x 2 ≤ 6 x 2 ≥ 4 x 1 ≤ 1 x 1 , x 2 ≥ 0 } = I L P 3 \left. \begin{array}{l} max\ z = 5x_1+8x_2\\ \begin{cases} 5x_1+9x_2 \leq 45\\ x_1+x_2 \leq 6\\ x_2 \geq 4\\ x_1 \leq 1\\ x1,x2 \geq 0 \end{cases} \end{array} \right\} =ILP3 max z=5x1+8x2⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧5x1+9x2≤45x1+x2≤6x2≥4x1≤1x1,x2≥0⎭⎪⎪⎪⎪⎪⎪⎪⎪⎬⎪⎪⎪⎪⎪⎪⎪⎪⎫=ILP3
m a x z = 5 x 1 + 8 x 2 { 5 x 1 + 9 x 2 ≤ 45 x 1 + x 2 ≤ 6 x 2 ≥ 4 x 1 ≥ 2 x 1 , x 2 ≥ 0 } = I L P 4 (4.6) \left. \begin{array}{l} max\ z = 5x_1+8x_2\\ \begin{cases} 5x_1+9x_2 \leq 45\\ x_1+x_2 \leq 6\\ x_2 \geq 4\\ x_1 \geq 2\\ x1,x2 \geq 0 \end{cases} \end{array} \right\} =ILP4 \tag{4.6} max z=5x1+8x2⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧5x1+9x2≤45x1+x2≤6x2≥4x1≥2x1,x2≥0⎭⎪⎪⎪⎪⎪⎪⎪⎪⎬⎪⎪⎪⎪⎪⎪⎪⎪⎫=ILP4(4.6)求解LP3得:
( x 1 , x 2 ) = ( 1 , 4 ) , z m a x = 40 (x_1, x_2)=(1, 4), z_{max}=40 (x1,x2)=(1,4),zmax=40
对于LP4,不难看出,无可行解。
(5)再修改界,此时我们又有 39 ≤ z ∗ ≤ 40 39\leq z^* \leq 40 39≤z∗≤40
(6)再分枝,继续对ILP3进行分枝,又得到
m a x z = 5 x 1 + 8 x 2 { 5 x 1 + 9 x 2 ≤ 45 x 1 + x 2 ≤ 6 x 2 ≥ 4 x 1 ≤ 1 x 2 ≤ 4 x 1 , x 2 ≥ 0 } = I L P 5 \left. \begin{array}{l} max\ z = 5x_1+8x_2\\ \begin{cases} 5x_1+9x_2 \leq 45\\ x_1+x_2 \leq 6\\ x_2 \geq 4\\ x_1 \leq 1\\ x_2 \leq 4\\ x1,x2 \geq 0 \end{cases} \end{array} \right\} =ILP5 max z=5x1+8x2⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧5x1+9x2≤45x1+x2≤6x2≥4x1≤1x2≤4x1,x2≥0⎭⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎫=ILP5
m a x z = 5 x 1 + 8 x 2 { 5 x 1 + 9 x 2 ≤ 45 x 1 + x 2 ≤ 6 x 2 ≥ 4 x 1 ≥ 2 x 2 ≥ 5 x 1 , x 2 ≥ 0 } = I L P 6 (4.7) \left. \begin{array}{l} max\ z = 5x_1+8x_2\\ \begin{cases} 5x_1+9x_2 \leq 45\\ x_1+x_2 \leq 6\\ x_2 \geq 4\\ x_1 \geq 2\\ x_2 \geq 5\\ x1,x2 \geq 0 \end{cases} \end{array} \right\} =ILP6 \tag{4.7} max z=5x1+8x2⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧5x1+9x2≤45x1+x2≤6x2≥4x1≥2x2≥5x1,x2≥0⎭⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎫=ILP6(4.7)
求解LP5得到:
( x 1 , x 2 ) = ( 1 , 4 ) , z m a x = 37 (x_1, x_2)=(1, 4),z_{max}=37 (x1,x2)=(1,4),zmax=37
求解LP6得到:
( x 1 , x 2 ) = ( 0 , 5 ) , z m a x = 40 (x_1, x_2)=(0, 5),z_{max}=40 (x1,x2)=(0,5),zmax=40
至此,所有的子问题都已探明,求解结束。寻找到上下界 39 ≤ z ∗ ≤ 40 39\leq z^*\leq 40 39≤z∗≤40。
我们得到了ILP0(即原问题)的最优解:
z ∗ = 40 z^*=40 z∗=40
第一步,先不考虑原问题的整数限制,求解相应的松弛问题,若求得最优解,检查它是否符合整数约束条件;如符合整数约束条件,即转下一步。
第二步,定界。在各分枝问题中,找出目标函数值最大者作为整数规划最优值 z ∗ z^* z∗的上界记为 U z Uz Uz,从已符合整数条件的分枝中,找出目标函数值最大者作为下界,记为 L z Lz Lz。即 L z ≤ z ∗ ≤ U z Lz\leq z^*\leq Uz Lz≤z∗≤Uz
第三步,分枝。根据对变量重要性的了解,在最优解中选择一个不符合整数条件的变量 x i = n u m x_i=num xi=num(num不为整数)则用下列两个约束条件:
⌊ n u m ⌋ ≤ x i ≤ ⌊ n u m ⌋ + 1 \lfloor num \rfloor \leq x_i \leq \lfloor num \rfloor+1 ⌊num⌋≤xi≤⌊num⌋+1
其中 ⌊ n u m ⌋ \lfloor num \rfloor ⌊num⌋表示不超过 n u m num num的最大整数,分别加入问题形成两个子问题。
第四步,应用对目标函数估界的方法,或对某一分枝重要性的了解,确定出首先要解的某一分枝的后继问题,并解此问题。若所获得的最优解符合整数条件,则就是原问题的解,若不符合整数条件,再回到第二步,并参照第四步终止后继问题。
在上述过程中,要不断应用分枝、定界、估界来进行判断。当我们求解某子问题的松弛问题时,只要出现下列情况之一,该问题就已探明:
已探明的子问题就不再用分枝了,如果所有的子问题都已探明,则原整数规划的最优解就一定可以求出,或可以判定它无解。
JAVA实现分支定界代码:
Github地址
package sy2;
import sy1.*;
/*
* 假设这里所解的整数规划问题的目标函数取的是max
*/
public class FenZhiDingJie {
double A[][]; //原矩阵的系数矩阵
String D[]; //原矩阵的符号矩阵
double b[]; //原矩阵的常数矩阵
public int count=0;
int index=-1;
public double C[];//目标函数的初始系数向量
public double Uz;//目标函数值下界
public double Lz;//目标函数值上界
public double z;//现在的目标函数值
public double X[];//定义最优解
public double zX[];//定义最优解
public double yX[];//定义最优解
public double Z;//定义整数线性规划的最优值
public double Ix[];//定义整数线性规划的最优解
public double As[][];
public double bs[];
public String Ds[];
public double Xs[];
public int lc;
int M,N;
//初始化分支定解法
FenZhiDingJie(double[][] a,double[] B,String[] d,double[] c){
M=B.length;
N=c.length;
A=a;
b=B;
D=d;
C=c;
X=new double[N];
zX=new double[N];
yX=new double[N];
Ix=new double[N];
}
//分支定解过程
public void FZDJ(double[][] a,double[] B,String[] d,double[] c,double x[]){
boolean flag1=true;
boolean flag2=true;
//利用两阶段法解出该整数线性规划的最优值的上界(第一次使用两阶段法)
while(count<10){
if(count==0){
System.out.println("\n第 "+count+" 次迭代");
TwoStepMethod tm=new TwoStepMethod(A,b,D,C);
if(!tm.flag){
break;
}
X=tm.X;
x=X;
Lz=0;
Uz=-tm.z;
System.out.print("该整数线性规划问题对应的松弛线性规划问题的最优解是:x={");
for(int i=0;i=Uz){
flag=true;//表示该分支继续往下分不可能找到一个可行解
}// if
else{
flag=false;
}
return flag;
}
//判断所给向量的元素是否全为整数如果不是返回对应第一个非整数的下标
public int AllInteger(double X[],int index){
boolean flag=true;
for(int i=0;i" ; } } return D; } 每次分支扩展参数过程 public double[][] tempA(double a[][],int m,int index){ double A[][]="new" double[m+1][N]; 对原约束条件添加一个限制 for(int i="0;i
package sy2;
import java.util.Scanner;
import sy1.TwoStepMethod;
/*
* 代码测试程序
*/
public class Text {
public static void main(String args[]){
int M=2,N=2;//M是约束条件个数,N是未知数个数
double A[][]=new double[M][N];
double b[]=new double[M];
String D[]=new String[M];//原符号向量
double C[]=new double[N];//原目标函数的系数向量
Scanner S=new Scanner(System.in);
for(int i=0;i