运筹系列8:Set partitioning问题的列生成方法

1. 应用场景

列生成算法是不断添加求解变量的算法,可参考论文。上一节我们介绍了约束条件存在分块结构的情形下可以使用单纯型法的判断规则进行列生成,下面我们介绍另一种场景,set-partitionning问题的列生成算法。
具体来说,场景如下:有 n n n个0-1变量 z 1 . . . z n z_1...z_n z1...zn,每个 z i z_i zi带着很多中间变量 x i , j x_{i,j} xi,j用来进行约束,这是个变量很多,约束也很多的模型。我们首先对问题模型进行转化,将所有 z i z_i zi的组合枚举出来,在枚举的过程中,就把约束条件都过了一遍,只有满足所有约束条件的组合才会保留下来。最后的枚举结果分别对应 y 1 . . . y m y_1...y_m y1...ym
不难看出, m m m n n n的指数形式,使用set-partitioning模型之后,变量的数量大的可怕。好消息是,原问题的约束条件比较紧,只有少数组合成立,可以通过一定的规则产生,这样m的数量比较小,问题就比较好解决。

2. 例1:cutting stock problem

来看网上流传很多的cutting stock problem的例子,问题如下:
我们有一些纸筒,每个纸筒16m。顾客需要裁剪的长度为:25个3m,20个6m,15个7m。要求在满足顾客需求的情况下,裁剪的纸筒数最小。
我们可以枚举出每筒可能的裁剪方案:
方案1:5个3m,即3+3+3+3+3
方案2:2个6m,即6+6
方案3:2个7m,即7+7
我们可以继续枚举下去:
4:6+6+3
5:6+3+3+3
6:7+3+3+3
7:7+6+3

仅使用前三种方案,我们用23筒(5个方案1,10个方案2,8个方案3)是肯定可以满足要求的,这算问题的一个上界。下面我们探索一下其他的切筒方式,看能不能给出下界。

一般性的,我们假设 P P P是所有可行的裁剪方案的集合(其中前3个可以设置为我们前面的3个裁剪方案),里面方案的总数为 n n n(我们并不需要确切的知道这个值是多少,只需要知道它很大)。令 a i j a_{ij} aij表示第 j j j种方案里类别 i i i的个数, y j y_j yj表示第 j j j种方案的选择个数,原问题可以变为:
min ⁡ y 1 + . . . + y n \min y_1+...+y_n miny1+...+yn
a 1 , 1 y 1 + a 1 , 2 y 2 + . . . + a 1 , n y n ≥ 25 a_{1,1}y_1+a_{1,2}y_2+...+a_{1,n}y_n \geq 25 a1,1y1+a1,2y2+...+a1,nyn25
a 2 , 1 y 1 + a 2 , 2 y 2 + . . . + a 2 , n y n ≥ 20 a_{2,1}y_1+a_{2,2}y_2+...+a_{2,n}y_n \geq 20 a2,1y1+a2,2y2+...+a2,nyn20
a 3 , 1 y 1 + a 3 , 2 y 2 + . . . + a 3 , n y n ≥ 15 a_{3,1}y_1+a_{3,2}y_2+...+a_{3,n}y_n \geq 15 a3,1y1+a3,2y2+...+a3,nyn15
其中
a 1 , 1 = 5 a_{1,1}=5 a1,1=5 a 2 , 1 = 0 a_{2,1}=0 a2,1=0 a 3 , 1 = 0 a_{3,1}=0 a3,1=0
a 1 , 2 = 0 a_{1,2}=0 a1,2=0 a 2 , 2 = 2 a_{2,2}=2 a2,2=2 a 3 , 2 = 0 a_{3,2}=0 a3,2=0
a 1 , 3 = 0 a_{1,3}=0 a1,3=0 a 2 , 3 = 0 a_{2,3}=0 a2,3=0 a 3 , 3 = 2 a_{3,3}=2 a3,3=2
对应最初的3种方案。
a i , j a_{i,j} ai,j满足条件: 3 ∗ a 1 , j + 6 ∗ a 2 , j + 7 ∗ a 3 , j ≤ 16 3*a_{1,j}+6*a_{2,j}+7*a_{3,j}\leq 16 3a1,j+6a2,j+7a3,j16(前面所说的列生成的规则)
注意我们在使用列生成算法的时候,将整数变量松弛为了连续变量。

用矩阵形式重新表达如下:
min ⁡ Σ j y j \min \Sigma_{j} y_j minΣjyj
s.t. A y ≥ b T Ay ≥ b^T AybT
A A A是一个矩阵, b = [ b 1 , . . . , b m ] b=[b_1,...,b_m] b=[b1,...,bm] y = [ y 1 , . . . , y n ] y=[y_1,...,y_n] y=[y1,...,yn]是向量;并且有重要的一点:set-covering的变量 y j y_j yj对应的列 a j = [ a 1 j , . . . , a m j ] T a_j=[a_{1j},...,a_{mj}]^T aj=[a1j,...,amj]T生成的规则,可以通过线性约束条件 B ∗ a j ≤ D B*a_j ≤ D BajD得到。这使得我们可以用线性规划的方法来求解子问题~
注意由于列生成算法求解的是松弛线性规划问题,因此对整数规划模型需要结合branch and bound算法进行。

2.1 限制主问题

首先用启发式算法找出一部分 A A A,比如说选出了 k k k列。然后我们的线性规划问题就变成了:
min y 1 + y 2 + . . . + y k y_1+y_2+...+y_k y1+y2+...+yk
s.t. a i , 1 ∗ y 1 + a i , 2 ∗ y 2 + . . . + a i , k ∗ y k ≥ b i a_{i,1}*y_1+a_{i,2}*y_2+...+a_{i,k}*y_k≥ b_i ai,1y1+ai,2y2+...+ai,kykbi i = 1... n i = 1...n i=1...n
相比原来的模型,相当于把 y k + 1 y_{k+1} yk+1~ y m y_m ym强制限制为非基变量了,称为限制主问题(Restricted Master Problem,RMP)。上面的限制主问题求解完成后,我们想使用单纯型法进行基变量的转换,看看 y k + 1 y_{k+1} yk+1~ y m y_m ym中,是否有可以转入基变量的列。检验数 σ = c N − π ∗ a j \sigma = c_N - \pi * a_j σ=cNπaj,并且 π = c B B − 1 π = c_BB^{-1} π=cBB1可以由求解器给出。我们要找出非基变量中最小的负数 σ \sigma σ,将其转入基变量。正如前面所述,我们这里使用线性规划来找这个新的列。

2.2 子问题

注意 c = [ 1 , . . . , 1 ] c = [1,...,1] c=[1,...,1],因此 min c N − π a j c_N - \pi a_j cNπaj等价于
min 1 − π ∗ a 1 - \pi *a 1πa
s.t. B ∗ a ≤ D B*a ≤ D BaD (列生成的规则)
称为子问题(sub problem)。如果目标函数最优值<0,就将新生成的列yk+1转入基变量,生成新的限制主问题进行求解。如此往复,直至子问题的目标函数≥0。

2.3 求解质量分析

一般性的,我们假设原问题为
Z = max ⁡ c x Z=\max cx Z=maxcx
A x = b , x ≥ 0 Ax=b,x\ge0 Ax=b,x0

RMP为
max ⁡ c x ˉ \max c\bar{x} maxcxˉ
A x ˉ = b , x ˉ ≥ 0 A\bar{x}=b,\bar{x}\ge0 Axˉ=b,xˉ0
z ˉ \bar{z} zˉ为RMP的最优解, z ∗ z^* z为原问题的最优解,我们有 z ∗ ≤ z ˉ z^*\le \bar{z} zzˉ

SP求得的最佳残差(负数)为 c ˉ ∗ \bar{c}^* cˉ,并令 k ≥ Σ x k\ge \Sigma x kΣx z ˉ \bar{z} zˉ同样也是对偶问题的最优解,因此我们有 z ˉ + c ˉ ∗ k ≤ z ∗ \bar{z}+ \bar{c}^*k\le z^* zˉ+cˉkz

在set-partitioning问题中,我们可以取 k = Σ x = x ∗ k= \Sigma x=x^* k=Σx=x,因此有 z ˉ / ( 1 − c ˉ ∗ ) ≤ z ∗ ≤ z ˉ \bar{z}/(1- \bar{c}^*)\le z^*\le \bar{z} zˉ/(1cˉ)zzˉ。同样,我们可以参考simplex的启发算法,令
在这里插入图片描述

在这里插入图片描述

2.4 迭代过程

2.4.1 第一轮

问题对应的初始解为 y 1 = 5 y_1=5 y1=5 y 2 = 10 y_2=10 y2=10 y 3 = 8 y_3=8 y3=8 y 4 = . . . y n = 0 y_4=...y_n=0 y4=...yn=0
限制主问题(restricted master problem)如下:
min ⁡ y 1 + y 2 + y 3 \min y_1+y_2+y_3 miny1+y2+y3
5 y 1 + 0 y 2 + 0 y 3 ≥ 25 5 y_1+0 y_2+0y_3 \geq 25 5y1+0y2+0y325
0 y 1 + 2 y 2 + 0 y 3 ≥ 20 0y_1+2y_2+0y_3 \geq 20 0y1+2y2+0y320
0 y 1 + 0 y 2 + 2 y 3 ≥ 15 0y_1+0y_2+2y_3 \geq 15 0y1+0y2+2y315

下面是pymprog的sensitivity输出:
在这里插入图片描述
对应 π = ( 0.2 , 0.5 , 0.5 ) \pi = (0.2, 0.5, 0.5) π=(0.2,0.5,0.5),我们把新转入的变量记作 a 4 = ( a 1 , 4 , a 2 , 4 , a 3 , 4 ) a_4 = (a_{1,4},a_{2,4},a_{3,4}) a4=(a1,4,a2,4,a3,4),则子问题为:
min 1 − 0.2 ∗ a 1 , 4 − 0.5 ∗ a 2 , 4 − 0.5 ∗ a 3 , 4 1 - 0.2*a_{1,4}-0.5*a_{2,4}-0.5*a_{3,4} 10.2a1,40.5a2,40.5a3,4
s.t. 3 ∗ a 1 , 4 + 6 ∗ a 2 , 4 + 7 ∗ a 3 , 4 ≤ 16 3*a_{1,4}+6*a_{2,4}+7*a_{3,4}\leq 16 3a1,4+6a2,4+7a3,416 (列生成的规则)
a i , j ∈ Z a_{i,j}\in Z ai,jZ
求解结果为 a 4 = ( 1 , 2 , 0 ) a_4=(1,2,0) a4=(1,2,0),检验数 σ = 1 − π ∗ a 4 = − 0.2 ≤ 0 \sigma = 1 - \pi * a_4 =-0.2\le 0 σ=1πa4=0.20。此时问题目标为22.5。
y 4 y_4 y4进基,把这个结果添加到主问题当中去,开始第二轮迭代。

2.4.2 第二轮

添加了 y 4 y_4 y4后,限制主问题为:
min ⁡ y 1 + y 2 + y 3 + y 4 \min y_1+y_2+y_3+y_4 miny1+y2+y3+y4
5 y 1 + 0 y 2 + 0 y 3 + 1 y 4 ≥ 25 5 y_1+0 y_2+0y_3+1y_4 \geq 25 5y1+0y2+0y3+1y425
0 y 1 + 2 y 2 + 0 y 3 + 2 y 4 ≥ 20 0y_1+2y_2+0y_3+2y_4 \geq 20 0y1+2y2+0y3+2y420
0 y 1 + 0 y 2 + 2 y 3 + 0 y 4 ≥ 15 0y_1+0y_2+2y_3+0y_4 \geq 15 0y1+0y2+2y3+0y415

直观上来看,是添加了一个新列,所以称为列生成算法。上面的主问题求解结果为:
在这里插入图片描述
对应 π = ( 0.2 , 0.4 , 0.5 ) \pi = (0.2, 0.4, 0.5) π=(0.2,0.4,0.5),我们把新转入的变量记作 a 5 = ( a 1 , 5 , a 2 , 5 , a 3 , 5 ) a_5 = (a_{1,5},a_{2,5},a_{3,5}) a5=(a1,5,a2,5,a3,5),则子问题为:
min 1 − 0.2 ∗ a 1 , 5 − 0.4 ∗ a 2 , 5 − 0.5 ∗ a 3 , 5 1 - 0.2*a_{1,5}-0.4*a_{2,5}-0.5*a_{3,5} 10.2a1,50.4a2,50.5a3,5
s.t. 3 ∗ a 1 , 5 + 6 ∗ a 2 , 5 + 7 ∗ a 3 , 5 ≤ 16 3*a_{1,5}+6*a_{2,5}+7*a_{3,5}\leq 16 3a1,5+6a2,5+7a3,516 (列生成的规则)
a i , j ∈ Z a_{i,j}\in Z ai,jZ
求解结果为 a 5 = ( 3 , 0 , 1 ) a_5=(3,0,1) a5=(3,0,1),检验数 σ = 1 − π ∗ a 5 = − 0.1 < 0 \sigma = 1 - \pi * a_5=-0.1< 0 σ=1πa5=0.1<0。此时问题目标为20.5。
y 5 y_5 y5进基,把这个结果添加到主问题当中去,开始第三轮迭代。

2.4.3 第三轮

添加了 y 5 y_5 y5后,限制主问题为:
min ⁡ y 1 + y 2 + y 3 + y 4 + y 5 \min y_1+y_2+y_3+y_4+y_5 miny1+y2+y3+y4+y5
5 y 1 + 0 y 2 + 0 y 3 + 1 y 4 + 3 y 5 ≥ 25 5 y_1+0 y_2+0y_3+1y_4 +3y_5 \geq 25 5y1+0y2+0y3+1y4+3y525
0 y 1 + 2 y 2 + 0 y 3 + 2 y 4 + 0 y 5 ≥ 20 0y_1+2y_2+0y_3+2y_4 +0y_5\geq 20 0y1+2y2+0y3+2y4+0y520
0 y 1 + 0 y 2 + 2 y 3 + 0 y 4 + 1 y 5 ≥ 15 0y_1+0y_2+2y_3+0y_4 +1y_5\geq 15 0y1+0y2+2y3+0y4+1y515

上面的主问题求解结果为:
在这里插入图片描述
对应 π = ( 0.166667 , 0.416667 , 0.5 ) \pi = (0.166667, 0.416667, 0.5) π=(0.166667,0.416667,0.5),我们把新转入的变量记作 a 6 = ( a 1 , 6 , a 2 , 6 , a 3 , 6 ) a_6 = (a_{1,6},a_{2,6},a_{3,6}) a6=(a1,6,a2,6,a3,6),则子问题为:
min 1 − 0.166667 ∗ a 1 , 6 − 0.416667 ∗ a 2 , 6 − 0.5 ∗ a 3 , 6 1 - 0.166667*a_{1,6}-0.416667*a_{2,6}-0.5*a_{3,6} 10.166667a1,60.416667a2,60.5a3,6
s.t. 3 ∗ a 1 , 6 + 6 ∗ a 2 , 6 + 7 ∗ a 3 , 6 ≤ 16 3*a_{1,6}+6*a_{2,6}+7*a_{3,6}\leq 16 3a1,6+6a2,6+7a3,616 (列生成的规则)
a i , j ∈ Z a_{i,j}\in Z ai,jZ
求解结果为 a 6 = ( 1 , 1 , 1 ) a_6=(1,1,1) a6=(1,1,1),检验数 σ = 1 − π ∗ a 6 = − 0.083334 < 0 \sigma = 1 - \pi * a_6=-0.083334< 0 σ=1πa6=0.083334<0。此时问题目标为20。
y 6 y_6 y6进基,把这个结果添加到主问题当中去,开始第三轮迭代。

2.4.4 第四轮

添加了 y 6 y_6 y6后,限制主问题为:
min ⁡ y 1 + y 2 + y 3 + y 4 + y 5 + y 6 \min y_1+y_2+y_3+y_4+y_5+y_6 miny1+y2+y3+y4+y5+y6
5 y 1 + 0 y 2 + 0 y 3 + 1 y 4 + 3 y 5 + y 6 ≥ 25 5 y_1+0 y_2+0y_3+1y_4 +3y_5+y_6 \geq 25 5y1+0y2+0y3+1y4+3y5+y625
0 y 1 + 2 y 2 + 0 y 3 + 2 y 4 + 0 y 5 + y 6 ≥ 20 0y_1+2y_2+0y_3+2y_4 +0y_5+y_6\geq 20 0y1+2y2+0y3+2y4+0y5+y620
0 y 1 + 0 y 2 + 2 y 3 + 0 y 4 + 1 y 5 + y 6 ≥ 15 0y_1+0y_2+2y_3+0y_4 +1y_5+y_6\geq 15 0y1+0y2+2y3+0y4+1y5+y615

上面的主问题求解结果为:
在这里插入图片描述
对应 π = ( 0.2 , 0.4 , 0.4 ) \pi = (0.2, 0.4, 0.4) π=(0.2,0.4,0.4),我们把新转入的变量记作 a 7 = ( a 1 , 7 , a 2 , 7 , a 3 , 7 ) a_7 = (a_{1,7},a_{2,7},a_{3,7}) a7=(a1,7,a2,7,a3,7),则子问题为:
min 1 − 0.2 ∗ a 1 , 7 − 0.4 ∗ a 2 , 7 − 0.4 ∗ a 3 , 7 1 - 0.2*a_{1,7}-0.4*a_{2,7}-0.4*a_{3,7} 10.2a1,70.4a2,70.4a3,7
s.t. 3 ∗ a 1 , 7 + 6 ∗ a 2 , 7 + 7 ∗ a 3 , 7 ≤ 16 3*a_{1,7}+6*a_{2,7}+7*a_{3,7}\leq 16 3a1,7+6a2,7+7a3,716 (列生成的规则)
a i , j ∈ Z a_{i,j}\in Z ai,jZ
求解结果为 a 7 = ( 3 , 1 , 0 ) a_7=(3,1,0) a7=(3,1,0),检验数 σ = 1 − π ∗ a 6 = 0 \sigma = 1 - \pi * a_6= 0 σ=1πa6=0,结束迭代,此时问题目标为19。

2.4.5 LP和MIP的差别

我们把下面的模型称为Kantorovich模型:
在这里插入图片描述
在这里插入图片描述

LP问题可以给出一个下界,bound为在这里插入图片描述
这个bound很直观,即假设纸可以拼接。
我们换一个例子
在这里插入图片描述

使用LP得到bound为:
在这里插入图片描述
和最优值156差别还是比较大的。

2.5 Julia调用GLPK代码示例

代码如下:

A = [[5,0,0],[0,2,0],[0,0,2]]
b = [25 20 15];
while true
    # main model
    model = Model(GLPK.Optimizer)
    @variable(model, y[1:length(A[1])]>=0)
    @objective(model, Min, sum(y))
    r=@constraint(model,[i=1:3],sum(A[i].*y)>=b[i]);
    optimize!(model)
    
    # sub model
    submodel = Model(GLPK.Optimizer)
    @variable(submodel, a[1:3]>=0, Int)
    @objective(submodel, Min, 1-sum(dual.(r).*a))
    @constraint(submodel,sum([3,6,7].*a)<=16);
    optimize!(submodel)
    delta = objective_value(submodel)
	
    if delta<-0.001
        A = [[A[i];Int(JuMP.value(a[i]))] for i in 1:3]
        @info objective_value(model),"add",Int.(JuMP.value.(a))
    else
        @info objective_value(model)
        break
    end
end

经过3轮迭代得到最优解
在这里插入图片描述

2.6 python调用cplex代码示例

使用下列代码求出最优解:

from pymprog import *
p = model('example')
y = p.var('y',6,int) # variables
p.minimize(sum(y), 'master')
r1 = 5*y[0]+ y[3]+3*y[4]+y[5]>= 25 
r2 = 2*y[1]+2*y[3]+y[5] >= 20 
r3 = 2*y[2] +y[4]+y[5]>= 15 
p.solve()
for i in range(6):
    print(y[i].primal)

求解结果为: y 1 = 1 , y 4 = 3 , y 5 = 1 , y 6 = 14 y_1=1,y_4=3,y_5=1,y_6=14 y1=1,y4=3,y5=1,y6=14,总计需要19个纸筒。
也可以将最后一轮的 y y y取整得到一个可行解: y 1 = 2 , y 4 = 3 , y 6 = 15 y_1=2,y_4=3,y_6=15 y1=2,y4=3,y6=15,需要20个纸筒。
这里给出第四轮的限制主问题和子问题的代码供参考:

from pymprog import *
p = model('master problem')
y = p.var('y',6) # variables
p.minimize(sum(y), 'master')
r1 = 5*y[0]+ y[3]+3*y[4]+y[5]>= 25 
r2 = 2*y[1]+2*y[3]+y[5] >= 20 
r3 = 2*y[2] +y[4]+y[5]>= 15 
p.solve()
p.sensitivity()
from pymprog import *
s = model('sub problem')
a = s.var('a',3) # variables
for i in range(3):
    a[i].kind = int
s.minimize(1-(0.2*a[0] + 0.4*a[1] +0.4*a[2]), 'sub')
3*a[0] +6*a[1] +7*a[2]<= 16 # mountain bike limit
s.solve()
print(s.vobj())
for i in range(3):
    print(a[i].primal)

然后下面给出直接求最优解的代码。pymprog用了一天都没有求出来,因此改用cplex进行求解:

import cplex
from cplex.exceptions import CplexError
my_obj = [0.0,0.0,0.0,1.0]*23
my_ub = [5.0,2.0,2.0,1.0]*23
my_lb = [0.0,0.0,0.0,0.0]*23
my_ctype = "IIII"*23
my_colnames = []
my_rhs = [25,20,15]+[0,16]*23
my_sense = "GGG"+"LL"*23
for i in range(23):
    my_colnames = my_colnames + ["x0,"+str(i),"x1,"+str(i),"x2,"+str(i),"y"+str(i)]

def populatebyrow(prob):
    prob.objective.set_sense(prob.objective.sense.minimize)
    prob.variables.add(obj=my_obj, lb=my_lb, ub=my_ub, types=my_ctype,names=my_colnames)
    row0 = [1.0,0.0,0.0,0.0]*23
    row1 = [0.0,1.0,0.0,0.0]*23
    row2 = [0.0,0.0,1.0,0.0]*23    
    rows = [[my_colnames, row0],
            [my_colnames, row1],
            [my_colnames, row2]]
    for i in range(23):
        row3 = [0.0,0.0,0.0,0.0]*23
        row3[i*4:i*4+4]=[1.0,1.0,1.0,-100.0]
        row4 = [0.0,0.0,0.0,0.0]*23
        row4[i*4:i*4+4]=[3.0,6.0,7.0,0.0]
        rows = rows+[[my_colnames, row3],
            [my_colnames, row4]]
    prob.linear_constraints.add(lin_expr=rows, senses=my_sense,rhs=my_rhs)

try:
    my_prob = cplex.Cplex()
    handle = populatebyrow(my_prob)
    my_prob.solve()
    
except CplexError as exc:
    print(exc)

print("Solution status = ", my_prob.solution.status[my_prob.solution.get_status()])
print("Solution value  = ", my_prob.solution.get_objective_value())
x = my_prob.solution.get_values()
for i in range(23):
    if x[i*4+3]>0:
        print(x[i*4:i*4+3])

结果如下:

CPXPARAM_Read_DataCheck                          1
Tried aggregator 1 time.
MIP Presolve modified 23 coefficients.
Reduced MIP has 49 rows, 92 columns, and 230 nonzeros.
Reduced MIP has 23 binaries, 69 generals, 0 SOSs, and 0 indicators.
Presolve time = 0.00 sec. (0.12 ticks)
Found incumbent of value 22.000000 after 0.00 sec. (0.48 ticks)
Probing time = 0.00 sec. (0.01 ticks)
Tried aggregator 1 time.
Reduced MIP has 49 rows, 92 columns, and 230 nonzeros.
Reduced MIP has 23 binaries, 69 generals, 0 SOSs, and 0 indicators.
Presolve time = 0.00 sec. (0.21 ticks)
Probing time = 0.00 sec. (0.01 ticks)
MIP emphasis: balance optimality and feasibility.
MIP search method: dynamic search.
Parallel mode: deterministic, using up to 4 threads.
Root relaxation solution time = 0.00 sec. (0.13 ticks)

        Nodes                                         Cuts/
   Node  Left     Objective  IInf  Best Integer    Best Bound    ItCnt     Gap

*     0+    0                           22.0000        0.0000           100.00%
      0     0        6.6667    38       22.0000        6.6667       30   69.70%
      0     0       10.2791    39       22.0000      Cuts: 62      143   53.28%
      0     0       18.0972    40       22.0000      Cuts: 80      213   17.74%
*     0+    0                           21.0000       18.0972            13.82%
      0     0       18.4688    35       21.0000      Cuts: 38      305   12.05%
      0     0       18.7500    19       21.0000      Cuts: 41      395   10.71%
      0     0       18.7500    12       21.0000      Cuts: 18      444   10.71%
      0     0       18.8667    10       21.0000      Cuts: 12      496   10.16%
*     0+    0                           19.0000       18.8667             0.70%
      0     0        cutoff             19.0000       18.8667      496    0.70%
Elapsed time = 0.18 sec. (7.56 ticks, tree = 0.01 MB, solutions = 3)

Implied bound cuts applied:  22
Mixed integer rounding cuts applied:  35
Zero-half cuts applied:  5
Gomory fractional cuts applied:  7

Root node processing (before b&c):
  Real time             =    0.19 sec. (7.57 ticks)
Parallel b&c, 4 threads:
  Real time             =    0.00 sec. (0.00 ticks)
  Sync time (average)   =    0.00 sec.
  Wait time (average)   =    0.00 sec.
                          ------------
Total (root+branch&cut) =    0.19 sec. (7.57 ticks)
Solution status =  MIP_optimal
Solution value  =  19.0
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 2.0, 0.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[1.0, 2.0, 0.0]
[1.0, 1.0, 1.0]
[1.0, 2.0, 0.0]
[1.0, 1.0, 1.0]
[5.0, 0.0, 0.0]
[1.0, 1.0, 1.0]
[1.0, 1.0, 1.0]
[3.0, 0.0, 1.0]
[1.0, 1.0, 1.0]

最终是19个。

3. 例子2:多货物配送问题

多个货物在有路径容量限制的图上G=(V,E)进行配送。令 x i , j l x^l_{i,j} xi,jl为货物 l l l是否在路径 i , j i,j i,j上进行配送, q l q^l ql为货物的配送量,直观建模为:
在这里插入图片描述
b i l = 1 b^l_i = 1 bil=1 if i i i is the source node of commodity l l l,let b i l = − 1 b^l_i =−1 bil=1if i i i is the target node of commodity l l l, and let b i l = 0 b^l_i = 0 bil=0 otherwise。
令P为path集合,我们使用set-partitioning模型重新建模:

在这里插入图片描述
其中 δ i j p δ^p_{ij} δijp be a constant denoting whether or not path p visits edge ( i j ) ∈ E (ij) \in E (ij)E
模型中多了一个等式约束,并且子问题不能用线性规划简单求解。
首先我们来看列生成的规则,Let π i j π_{ij} πij ≤0 be the dual of constraint (19) and σ l ∈ R σ^l ∈R σlR be the dual of constraint (20),
则reduced cost for a column p 为:
在这里插入图片描述

我们有列生成的限制要求:
在这里插入图片描述
我们可以将距离矩阵从 c i j c_{ij} cij替换为 c i j − π i j c_{ij}-\pi_{ij} cijπij,上面这个不等式的左边可以理解为寻找每个商品 l l l在新的距离矩阵下的最短路,然后看是否小于 σ l \sigma^l σl,如果满足则将此路径p添加进限制主问题中。

4. 例子3:bin packing问题

bin的容量为 W W W,有 n n n个物品,大小为: L = w 1 , . . . , w n L={w_1,...,w_n} L=w1,...,wn。将物品放在bin中,使bin的数量最少。
使用flow模型进行建模:
在这里插入图片描述
如上图,W=5,L={3,2},下半部分是一条可行路径。目标函数是路径条数最小化,约束则是每个w都要有,并且中间的点需要流量平衡。
Min z
s.t.
在这里插入图片描述

  • 19
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值