02. 整数规划
定义
规划中的变量 (部分或全部) 限制为整数时,称为整数规划。
若在线性规划模型中变量限制为整数,则称为整数线性规划。
分类:
- 变量全限制为整数时,称纯 (完全) 整数规划;
- 变量部分限制为整数时,称混合整数规划。
求解方法
分枝定界法
思路:将可行解空间分割为越来越小的子集,对每个子集内的解集计算目标下界,超出已知可行解集目标值的子集不再进一步分枝。
步骤
-
**分枝:**在问题中任选一个不符合整数条件的变量 x j = b j x_j=b_j xj=bj,取小于 b j b_j bj 的最大整数和大于 b j b_j bj 的最小整数,构造新的约束条件
x j ≤ [ b j ] , x j ≥ [ b j ] + 1 x_j\le[b_j],x_j\ge[b_j]+1 xj≤[bj],xj≥[bj]+1
将约束条件加入原问题,构造两个新问题; -
**定界:**对于新问题的解,从符合整数条件的分枝中,找出目标函数值最大作为新的下界;
-
**比较与剪枝:**若分枝的解小于下界,则去除该分枝;若分枝的解大于下界且不符合整数条件,重复步骤 1,直到解等于下界。
例子
max z = 40 x 1 + 90 x 2 \max z=40x_1+90x_2 maxz=40x1+90x2
{ 9 x 1 + 7 x 2 ≤ 56 7 x 1 + 20 x 2 ≤ 70 x 1 , x 2 ≥ 0 x 1 , x 2 ∈ Z \left\{\begin{aligned} & 9x_1+7x_2\le56 \\ & 7x_1+20x_2\le70 \\ & x_1,x_2\ge0 \\ & x_1,x_2\in Z \end{aligned}\right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧9x1+7x2≤567x1+20x2≤70x1,x2≥0x1,x2∈Z
1. 求解与定界
记问题
B
B
B,首先不考虑整数限制,得
x
1
=
4.8092
,
x
2
=
1.8168
,
z
=
355.8779
x_1=4.8092,x_2=1.8168,z=355.8779
x1=4.8092,x2=1.8168,z=355.8779
而 x 1 = 0 , x 2 = 0 x_1=0,x_2=0 x1=0,x2=0 时 z = 0 z=0 z=0,则为 z ∗ z^* z∗ 的下界,记 z ‾ \underline{z} z。
即
z
‾
=
0
\underline{z}=0
z=0
2. 分枝再求解
对
x
1
,
x
2
x_1,x_2
x1,x2 任选一个进行分枝,设选
x
1
x_1
x1 分枝,有:
x
1
≤
[
4.8092
]
=
4
,
x
1
≥
[
4.8092
]
+
1
=
5
x_1\le[4.8092]=4,x1\ge[4.8092]+1=5
x1≤[4.8092]=4,x1≥[4.8092]+1=5
对于
x
1
≤
4
x_1\le4
x1≤4,构成新的约束条件,记问题
B
1
B_1
B1:
{
9
x
1
+
7
x
2
≤
56
7
x
1
+
20
x
2
≤
70
0
≤
x
1
≤
4
x
2
≥
0
\left\{\begin{aligned} & 9x_1+7x_2\le56 \\ & 7x_1+20x_2\le70 \\ & 0\le x_1\le4 \\ & x_2\ge0 \end{aligned}\right.
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧9x1+7x2≤567x1+20x2≤700≤x1≤4x2≥0
解得
x
1
=
4
,
x
2
=
2.1
,
z
=
349
x_1=4,x_2=2.1,z=349
x1=4,x2=2.1,z=349
对于
x
1
≥
5
x_1\ge5
x1≥5,构成新的约束条件,记问题
B
2
B_2
B2:
{
9
x
1
+
7
x
2
≤
56
7
x
1
+
20
x
2
≤
70
x
1
≥
5
x
2
≥
0
\left\{\begin{aligned} & 9x_1+7x_2\le56 \\ & 7x_1+20x_2\le70 \\ & x_1\ge5 \\ & x_2\ge0 \end{aligned}\right.
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧9x1+7x2≤567x1+20x2≤70x1≥5x2≥0
解得
x
1
=
5
,
x
2
=
1.57
,
z
=
341.4
x_1=5,x_2=1.57,z=341.4
x1=5,x2=1.57,z=341.4
3. 再定界
B
1
,
B
2
B_1,B_2
B1,B2 的解均不满足整数条件,下界不变,即
z
‾
=
0
\underline{z}=0
z=0
两个问题的解均不等于下界,继续分枝。
4. 再分枝再求解
对问题
B
1
B_1
B1 再分枝,由于
x
1
x_1
x1 满足整数条件,选
x
2
x_2
x2:
x
2
≤
[
2.1
]
=
2
,
x
2
≥
[
2.1
]
+
1
=
3
x_2\le[2.1]=2,x_2\ge[2.1]+1=3
x2≤[2.1]=2,x2≥[2.1]+1=3
分别构成问题
B
11
,
B
12
B_{11},B_{12}
B11,B12。
最优解分别为:
- B 11 : x 1 = 4 , x 2 = 2 , z = 340 B_{11}: x_1=4,x_2=2,z=340 B11:x1=4,x2=2,z=340
- B 12 : x 1 = 1.43 , x 2 = 3 , z = 327.14 B_{12}: x_1=1.43,x_2=3,z=327.14 B12:x1=1.43,x2=3,z=327.14
同样对问题 B 2 B_2 B2 再分枝,有:
-
B 21 : x 1 = 5.44 , x 2 = 1 , z = 308 B_{21}: x_1=5.44,x_2=1,z=308 B21:x1=5.44,x2=1,z=308
-
B 22 B_{22} B22 无可行解
5. 再定界
B
11
,
B
12
,
B
21
,
B
22
B_{11},B_{12},B_{21},B_{22}
B11,B12,B21,B22 中,
B
11
B_{11}
B11 满足整数条件,作为下界,即
z
‾
=
340
\underline{z}=340
z=340
其余分枝解均小于下界,被剪枝,保留
B
11
B_{11}
B11。
而
B
11
B_{11}
B11 满足整数条件,无需继续分枝,作为最终解,即
x
1
=
4
,
x
2
=
2
,
z
=
340
x_1=4,x_2=2,z=340
x1=4,x2=2,z=340
过滤隐枚举法
思路:排除掉不可能的变量取值集合,只检查变量取值组合的一部分,就能求到问题的最优解。
过滤隐枚举法是解 0-1 型整数规划的一种解法。
步骤
- 试探求一个可行解 x = ( x 1 , x 2 , … , x n ) x=(x1,x2,\dots,x_n) x=(x1,x2,…,xn),代入得 z = j 1 z=j_1 z=j1;
- 增加约束条件 z ≥ j 1 z\ge j_1 z≥j1;
- 继续试探求解并更新约束条件,从而抬高过滤门槛,减少计算量。
蒙特卡洛法
对可行解集进行随机取样,选取部分解集代入计算。
Python 代码
利用 cvxpy 包可以直接进行整数规划的求解。
对于问题:
min
x
1
,
x
2
z
=
40
x
1
+
90
x
2
\min_{x_1,x_2}z=40x_1+90x_2
x1,x2minz=40x1+90x2
s . t . { 9 x 1 + 7 x 2 ≤ 56 , 7 x 1 + 20 x 2 ≥ 70 , x 1 , x 2 ≥ 0 , x 1 , x 2 ∈ Z . s.t.\left\{\begin{aligned} & 9x_1+7x_2\le56,\\ & 7x_1+20x_2\ge70,\\ & x_1,x_2\ge0,\\ & x_1,x_2\in Z. \end{aligned}\right. s.t.⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧9x1+7x2≤56,7x1+20x2≥70,x1,x2≥0,x1,x2∈Z.
代码如下:
# %%
import numpy as np
import cvxpy as cp
# %%
# 目标函数形如 min c^T·x
c = np.array([40, 90])
# 约束形如 a·x <= b
a = np.array([[9, 7],
[-7, -20]])
b = np.array([56, -70])
# 两个整数决策变量
x = cp.Variable(2, integer=True)
# 目标函数
z = cp.Minimize(c * x)
# 约束条件
cons = [a * x <= b,
x >= 0]
# 问题模型
prob = cp.Problem(z, cons)
prob.solve(solver='GLPK_MI', verbose=True)
# %%
print('best z =', prob.value)
print('best x =', x.value)
输出:
best z = 350.0
best x = [2. 3.]
因此有最优解
x
1
=
2
,
x
2
=
3
x_1=2,x_2=3
x1=2,x2=3
时,
z
z
z 取得最小值 350.