习题

习题2.1

   试将下述非线性的0-1规划问题转换成线性的0-1规划问题
m a x z = x 1 + x 1 x 2 − x 3 s . t . = { − 2 x 1 + 3 x 2 + x 3 ≤ 3 x j = 0 或 1 ,    j = 1 , 2 , 3 max z = x_1+x_1x_2-x_3\\ s.t.= \begin{cases} -2x_1 + 3x_2+x_3 \leq 3\\ x_j = 0 \text{或}1,\ \ j = 1,2,3 \end{cases} maxz=x1+x1x2x3s.t.={2x1+3x2+x33xj=01,  j=1,2,3

算法设计

  做变量替换 y = x 1 x 2 y = x_1x_2 y=x1x2,则有如下关系:
x 1 + x 2 − 1 ≤ y ≤ x 1 x 1 + x 2 − 1 ≤ y ≤ x 2 x_1+x_2-1 \leq y \leq x_1 \\ x_1 + x_2 -1 \leq y \leq x_2 x1+x21yx1x1+x21yx2
  从而得到如下的线性0-1规划
m a x z = x 1 + y − x 3 s . t . = { − 2 x 1 + 3 x 2 + x 3 ≤ 3 x 1 + x 2 − 1 ≤ y ≤ x 1 x 1 + x 2 − 1 ≤ y ≤ x 2 x j = 0 或 1 ,    j = 1 , 2 , 3 y = 0 或 1 max z = x_1 + y - x_3\\ s.t.= \begin{cases} -2x_1 + 3x_2 + x_3 \leq 3\\ x_1 + x_2 -1 \leq y \leq x_1\\ x_1 + x_2 -1 \leq y \leq x_2\\ x_j = 0 或 1, \ \ j = 1,2,3\\ y = 0或1 \end{cases} maxz=x1+yx3s.t.=2x1+3x2+x33x1+x21yx1x1+x21yx2xj=01,  j=1,2,3y=01

习题2.2

  某市为方便小学生上学,拟在新建的8个居民小区 A 1 , A 2 , . . . , A 8 A_1,A_2,...,A_8 A1,A2,...,A8增设若干所小学,经过论证知备选校址有 B 1 , B 2 , . . . , B 6 B_1,B_2,...,B_6 B1,B2,...,B6,它们能够覆盖的居民小区如下表所示。

B 1 B_1 B1 B 2 B_2 B2 B 3 B_3 B3 B 4 B_4 B4 B 5 B_5 B5 B 6 B_6 B6
A 1 , A 5 , A 7 A_1,A_5,A_7 A1,A5,A7 A 1 , A 2 , A 5 , A 8 A_1,A_2,A_5,A_8 A1,A2,A5,A8 A 1 , A 3 , A 5 A_1,A_3,A_5 A1,A3,A5 A 2 , A 4 , A 8 A_2,A_4,A_8 A2,A4,A8 A 3 , A 6 A_3,A_6 A3,A6 A 4 , A 6 , A 8 A_4,A_6,A_8 A4,A6,A8

  试建立一个数学模型,确定出最小个数的建校地址,使其能够覆盖所有的居民小区

算法设计

  令
x i = { 1 ,     在 备 选 校 址 B i 建 学 校 0 ,     在 备 选 校 址 B i 不 建 学 校 x_{i} = \begin{cases} 1,\ \ \ 在备选校址B_{i}建学校\\ 0,\ \ \ 在备选校址B_{i}不建学校\\ \end{cases} xi={1,   Bi0,   Bi
  小区 A 1 A_{1} A1可以被备选校址B_1、B_2、B_3处所建的学校覆盖,则有约束条件
x 1 + x 2 + x 3 ≥ 1 x_1 + x_2 + x_3 \geq 1 x1+x2+x31
  依次类推,建立如下0-1整数规划模型:
m i n ∑ i = 1 6 x i s . t . = { x 1 + x 2 + x 3 ≥ 1 x 2 + x 4 ≥ 1 x 3 + x 5 ≥ 1 x 4 + x 6 ≥ 1 x 5 + x 6 ≥ 1 x 1 ≥ 1 x 2 + x 4 + x 6 ≥ 1 x i = 0 或 1 ,     i = 1 , 2 , . . . , 8 min \sum^{6}_{i = 1}x_i\\ s.t. = \begin{cases} x_1 + x_2 + x_3 \geq 1 \\ x_2 + x_4 \geq 1 \\ x_3 + x_5 \geq 1 \\ x_4 + x_6 \geq 1 \\ x_5 + x_6 \geq 1 \\ x_1 \geq 1\\ x_2 + x_4 + x_6 \geq 1 \\ x_{i} = 0 或 1,\ \ \ i = 1,2,...,8 \end{cases} mini=16xis.t.=x1+x2+x31x2+x41x3+x51x4+x61x5+x61x11x2+x4+x61xi=01,   i=1,2,...,8

# 决策变量
n = 8
# nonneg参数,变量是否为非负
x = cp.Variable(n,nonneg = True)

# 约束1
A1 = np.array([[1,1,1,0,0,0,0,0],
              [0,1,0,1,0,0,0,0],
              [0,0,1,0,1,0,0,0],
              [0,0,0,1,0,1,0,0],
              [0,0,0,0,1,1,0,0],
              [1,0,0,0,0,0,0,0],
              [0,1,0,1,0,1,0,0]])
b1 = np.array([1,1,1,1,1,1,1])

# 约束2
A2 = np.ones((8, 8))
for i in range(A2.shape[0]):
    for j in range(A2.shape[1]):
        if i == j:
            pass
        else:
            A2[i, j] = A2[i, j]*0

b2 = np.array([0,0,0,0,0,0,0,0])
# 约束3
A3 = np.ones((8, 8))
for i in range(A3.shape[0]):
    for j in range(A3.shape[1]):
        if i == j:
            pass
        else:
            A3[i, j] = A3[i, j]*0
b3 = np.array([1,1,1,1,1,1,1,1])

# 目标函数
c = np.array([1,1,1,1,1,1,1,1])

# 定义问题,添加约束条件
prob = cp.Problem(cp.Minimize(c.T @ x),
                  [A1 @ x >= b1,
                  A2 @ x >= b2,
                  A3 @ x <= b3])

# 求解
ans = prob.solve(solver=cp.GLOP)
# 输出结果
print("目标函数最小值:", ans)
# 对x向量各元素取整数后再输出
print(x.value)

输出

目标函数最小值: 3.0
[ 1. -0.  0.  1.  1. -0. -0. -0.]

习题2.3

  某公司新购置了某种设备6台,欲分配给下属的4个企业,每个企业至少获订一台设备,已知各企业获得这种设备后年创利润如下表所示,单位为千万元。问应如何分配这些设备能使年创利润最大,最大利润是多少?

设备
14234
26455
37676
47886
57986
671086

算法设计

  用 j = 1 , 2 , 3 , 4 j = 1,2,3,4 j=1,2,3,4分别表示甲、乙、丙、丁4个企业, c i j c_{ij} cij表示第 i ( i = 1 , 2 , . . . , 6 ) i(i= 1,2,...,6) i(i=1,2,...,6)台设备分配给第j个企业创造的利润,引进0-1变量:
x i j = { 1 ,     第 i 台 设 备 分 配 给 第 j 个 企 业 0 ,     第 i 台 设 备 不 分 配 给 第 j 个 企 业 x_{ij} = \begin{cases} 1,\ \ \ 第i台设备分配给第j个企业 \\ 0,\ \ \ 第i台设备不分配给第j个企业\\ \end{cases} xij={1,   ij0,   ij
  数学模型为:
m a x ∑ i = 1 6 ∑ j = 1 4 c i j x i j s . t . = { ∑ i = 1 6 ≥ 1 ,    j = 1 , 2 , 3 , 4 ∑ j = 1 4 ≥ 1 ,    i = 1 , 2 , . . . , 6 x i j = 0 或 1 ,    i = 1 , 2 , . . . 6 ; j = 1 , 2 , 3 , 4 max \sum_{i = 1}^{6} \sum_{j = 1}^{4}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{6}_{i = 1} \geq 1,\ \ j = 1,2,3,4\\ \sum\limits^{4}_{j = 1}\geq1,\ \ i = 1,2,...,6\\ x_{ij} = 0 或 1,\ \ i = 1,2,...6;j = 1,2,3,4 \end{cases} maxi=16j=14cijxijs.t.=i=161,  j=1,2,3,4j=141,  i=1,2,...,6xij=01,  i=1,2,...6;j=1,2,3,4

  • 这里用到了矩阵的点乘,需要用函数multiply,不能直接用python内置的矩阵乘法c * x会报维度错误。函数说明参考
# 决策变量
n = (6,4)
# nonneg参数,变量是否为非负
x = cp.Variable(n,nonneg = True)

# 约束1
b1 = np.ones((6,4))
c = np.array([[4,2,3,4],
              [6,4,5,5],
              [7,6,7,6],
              [7,8,8,6],
              [7,9,8,6],
              [7,10,8,6]])

# 定义问题,添加约束条件
prob = cp.Problem(cp.Maximize(cp.sum(cp.sum(cp.multiply(c,x),axis = 1),axis = 0)),
                 [cp.sum(x,axis = 0) >= 1,
                  cp.sum(x,axis = 1) == 1,
                  x <= b1])

# 求解
ans = prob.solve(solver=cp.GLOP)
# 输出结果
print("目标函数最大值:", ans)
# 对x向量各元素取整数后再输出
print(x.value)

输出

目标函数最大值: 44.0
[[ 0. -0. -0.  1.]
 [ 1. -0. -0. -0.]
 [ 0. -0.  1. -0.]
 [-0. -0.  1. -0.]
 [-0.  1. -0. -0.]
 [-0.  1. -0. -0.]]

习题2.4

  有一场由4个项目(高低杠、平衡木、跳马、自由体操)组成的女子体操团体赛,赛程规定:每个队最多允许10名运动员参赛,每一个项目可以有6名选手参加。每个选手参赛的成绩评分从高到低依次为10、9.9、9.8、…、0.1、0。每个代表队的总分是参赛选手所得总分之和,总分最多的代表队为优胜者。此外,还规定每个运动员只能参加全能比赛(4项全参加)与单项比赛这两类中的一类,参加单项比赛的每个运动员至多只能参加3个单项。每个队应有4人参加全能比赛,其余运动员参加单项比赛。
  现某代表队的教练已经对其所带领的10名运动员参加各个项目的成绩进行了大量测试,教练发现每个运动员在每个单项上的成绩稳定在4个得分上,她们得到这些成绩的相应概率也由统计得出,试解答以下问题:
  (1)每个选手的各单项得分按最悲观估算,在此前提下,请为该队排出一个出场阵容,使该队团体总分尽可能高;每个选手的各单项得分按均值估算,在此前提下,请为该队排出一个出场阵容,使该队团队总分尽可能高。
  (2)若对以往的资料及近期各种信息进行分析得到:本次夺冠的团体总分估计不少于236.2分,该队为了夺冠应排出怎样的阵容?以该阵容出战,其夺冠的前景如何?得分前景又如何?它有90%的把握战胜怎样水平的对手?

算法设计1

  • i = 1 , 2 , 3 , 4 i = 1,2,3,4 i=1,2,3,4分别表示高低杠、平衡木、跳马、自由体操4项运动。引进决策变量:
    x i j = { 1 ,     第 j 个 人 参 加 第 i 个 项 目 0 ,     第 j 个 人 不 参 加 第 i 个 项 目 x_{ij} = \begin{cases} 1,\ \ \ 第j个人参加第i个项目 \\ 0,\ \ \ 第j个人不参加第i个项目\\ \end{cases} xij={1,   ji0,   ji
    建立如下的非线性整数规划模型:
    m i n ∑ i = 1 4 ∑ j = 1 6 c i j x i j s . t . = { ∑ j = 1 10 x i j = 6 ,    i = 1 , 2 , 3 , 4 ∑ j = 1 10 ∏ i = 1 4 x i j = 4 min \sum^{4}_{i = 1}\sum^{6}_{j = 1}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{10}_{j = 1}x_{ij} = 6,\ \ i = 1,2,3,4\\ \sum\limits^{10}_{j = 1}\prod\limits^{4}_{i = 1}x_ij = 4\\ \end{cases} mini=14j=16cijxijs.t.=j=110xij=6,  i=1,2,3,4j=110i=14xij=4
    引入0-1变量:
    y j = { 1 ,     第 j 个 人 参 加 全 能 比 赛 0 ,     第 j 个 人 不 参 加 全 能 比 赛 y_{j} = \begin{cases} 1,\ \ \ 第j个人参加全能比赛 \\ 0,\ \ \ 第j个人不参加全能比赛\\ \end{cases} yj={1,   j0,   j
    将非线性整数规划模型转换为0-1整数线性规划模型:
    m i n ∑ i = 1 4 ∑ j = 1 6 c i j x i j s . t . = { ∑ j = 1 10 x i j = 6 ,    i = 1 , 2 , 3 , 4 4 y j ≤ ∑ i = 1 4 x i j ≤ 3 + y j ,    j = 1 , 2 , . . . , 10 ∑ j = 1 10 y j = 4 min \sum^{4}_{i = 1}\sum^{6}_{j = 1}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{10}_{j = 1}x_{ij} = 6,\ \ i = 1,2,3,4\\ 4y_{j} \leq \sum\limits^{4}_{i = 1}x_{ij} \leq 3 + y_{j},\ \ j = 1,2,...,10\\ \sum\limits^{10}_{j = 1}y_{j} = 4 \end{cases} mini=14j=16cijxijs.t.=j=110xij=6,  i=1,2,3,44yji=14xij3+yj,  j=1,2,...,10j=110yj=4
  • 变量约束条件改为布尔变量boolean = True,或整数变量integer = True,但是需要注意的是如果使用整数变量,最后需要添加条件x >= 0,x <= 1
  • 更换求解器,以前的GLOP求解器无法解决有布尔变量的线性规划,所以将求解器换成GLPK_MI
  • 如果提示求解器未安装,请使用pip install cvxopt,然后再使用cp.installed_solvers() ,查看已安装的求解器
  • 以前使用GLOP时语法是prob.solve(solver=cp.GLOP),现在使用GLPK_MI,语法变为prob.solve(solver='GLPK_MI')
  • 数据下载
data = np.loadtxt("../input/math-modeling/data2_4.txt")
fen = data[:,0:20:2]
gai = data[:,1:20:2]
low = np.zeros([4,10])
zhun = np.zeros([4,10])
for i in range(0,4):
    for j in range(0,10):
        low[i,j] = fen[4*i,j]
        zhun[i,j] = fen[4*i:4*(i+1),j] @ gai[4*i:4*(i+1),j]
# 决策变量
n = (4,10)
z = 10
# nonneg参数,变量是否为非负
x = cp.Variable(n,boolean = True)
y = cp.Variable(z,boolean = True)

# 定义问题,添加约束条件
prob = cp.Problem(cp.Maximize(cp.sum(cp.sum(cp.multiply(low,x)))),
                 [cp.sum(x,axis = 1) == 6,
                  cp.sum(y,axis = 0) == 4,
                  4 * y <= cp.sum(x,axis = 0),
                  cp.sum(x,axis = 0) <= 3+y])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最大值:", ans)
# 对x向量各元素取整数后再输出
print(x.value)

输出

目标函数最大值: 212.3
[[0. 1. 0. 0. 1. 1. 1. 0. 1. 1.]
 [0. 1. 0. 1. 1. 1. 0. 1. 1. 0.]
 [1. 1. 0. 1. 1. 1. 0. 0. 1. 0.]
 [0. 1. 1. 0. 1. 1. 0. 0. 1. 1.]]
# 定义问题,添加约束条件
prob = cp.Problem(cp.Maximize(cp.sum(cp.sum(cp.multiply(zhun,x)))),
                 [cp.sum(x,axis = 1) == 6,
                  cp.sum(y,axis = 0) == 4,
                  4 * y <= cp.sum(x,axis = 0),
                  cp.sum(x,axis = 0) <= 3+y,
                  x>=0,x<=1,y>=0,y<=1])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最大值:", ans)
# 对x向量各元素取整数后再输出
print(x.value)

输出

目标函数最大值: 225.1
[[0. 1. 1. 0. 0. 1. 1. 0. 1. 1.]
 [0. 1. 1. 0. 1. 0. 0. 1. 1. 1.]
 [1. 1. 1. 1. 0. 0. 0. 0. 1. 1.]
 [0. 1. 1. 0. 1. 0. 0. 1. 1. 1.]]

算法设计2

  将团体总分236.2作为一个约束条件,得分的概率作为目标函数,建立0-1整数规划模型。用 k = 1 , 2 , 3 , 4 k = 1,2,3,4 k=1,2,3,4记运动员参加项目得到了第 K K K种得分, a i j k a_{ijk} aijk b i j k b_{ijk} bijk分别表示第 j j j个运动员参加第 i i i个项目得到的第 k k k种得分值及概率。记 p i j p_{ij} pij为运动员 j j j参加第 i i i个项目的某种得分的概率。
  引入0-1变量:
z i j k = { 1 ,     运 动 员 j 参 加 项 目 i 得 到 a i j k 分 0 ,     运 动 员 j 参 加 i 项 目 没 得 到 a i j k 分 z_{ijk} = \begin{cases} 1,\ \ \ 运动员j参加项目i得到a_{ijk}分 \\ 0,\ \ \ 运动员j参加i项目没得到a_{ijk}分\\ \end{cases} zijk={1,   jiaijk0,   jiaijk
  建立如下的整数规划模型:
m a x    ∏ i = 1 4 ∏ j = 1 10 p i j x i j s . t . = { ∑ j = 1 10 x i j = 6 ,    i = 1 , 2 , 3 , 4 4 y j ≤ ∑ i = 1 4 x i j ≤ 3 + y j ∑ j = 1 10 y j = 4 p i j = ∑ k = 1 4 b i j k z i j k ,   i = 1 , 2 , 3 , 4 ;   j = 1 , 2 , ⋯   , 10 c i j = ∑ k = 1 4 a i j k z i j k ,   i = 1 , 2 , 3 , 4 ;   j = 1 , 2 , ⋯   , 10 ∑ i = 1 4 ∑ j = 1 10 c i j x i j ≥ 236.2 ∑ j = 1 4 z i j k ≤ 1 ,   i = 1 , 2 , 3 , 4 ;   j = 1 , 2 , ⋯   , 10 x i j = ∑ k = 1 4 z i j k ,    i = 1 , 2 , 3 , 4 ; j = 1 , 2 , ⋯   , 10 max\ \ \prod^{4}_{i = 1}\prod^{10}_{j = 1}p_{ij}^{x_{ij}}\\ s.t. = \begin{cases} \sum\limits^{10}_{j = 1}x_{ij} = 6,\ \ i = 1,2,3,4\\ 4y_{j} \leq \sum\limits^{4}_{i = 1}x_{ij}\leq 3+y_{j}\\ \sum\limits^{10}_{j = 1}y_j = 4\\ p_{ij} = \sum\limits^{4}_{k = 1}b_{ijk}z_{ijk},\ i = 1,2,3,4;\ j = 1,2,\cdots,10\\ c_{ij} = \sum\limits^{4}_{k = 1}a_{ijk}z_{ijk},\ i = 1,2,3,4;\ j = 1,2,\cdots,10\\ \sum\limits_{i = 1}^{4}\sum\limits_{j = 1}^{10}c_{ij}x_{ij} \geq 236.2\\ \sum\limits_{j = 1}^{4}z_{ijk} \leq 1,\ i = 1,2,3,4;\ j = 1,2,\cdots,10\\ x_{ij} = \sum\limits^{4}_{k = 1}z_{ijk},\ \ i = 1,2,3,4;j = 1,2,\cdots,10 \end{cases} max  i=14j=110pijxijs.t.=j=110xij=6,  i=1,2,3,44yji=14xij3+yjj=110yj=4pij=k=14bijkzijk, i=1,2,3,4; j=1,2,,10cij=k=14aijkzijk, i=1,2,3,4; j=1,2,,10i=14j=110cijxij236.2j=14zijk1, i=1,2,3,4; j=1,2,,10xij=k=14zijk,  i=1,2,3,4;j=1,2,,10

习题2.5

  某单位需要加工制作 100 100 100套钢架,每套用长为 2.9 m 2.9m 2.9m 2.1 m 2.1m 2.1m 1 m 1m 1m的圆钢各一根。已知原料长 6.9 m 6.9m 6.9m。(1)如何下料,使用原材料最省?(2)若下料方式不超过三种,则应如何下料,使用的原材料最省?

算法设计1

  • 使用枚举法列出所有可行的套裁方案。
目标ABCDEFG
2.91200001
2.10032101
14102461
合计6.96.86.36.26.166
料头00.10.60.70.80.90.9
  • 为了保证完成100套钢架,所使用原材料最省,可以混合使用各种下料方案。设按方案A、B、C、D、E、F、G下料的原材料根数分别为 x i ( i = 1 , 2 , . . . , 7 ) x_{i}(i = 1,2,...,7) xi(i=1,2,...,7),根据上表的数据建立如下线性规划模型:
    m i n    ∑ i = 1 7 x i s . t . = { x 1 + 2 x 2 + x 7 ≥ 100 3 x 3 + 2 x 4 + x 5 + x 7 ≥ 100 4 x 1 + x 2 + 2 x 4 + 4 x 5 + 6 x 6 + x 7 ≥ 100 , x i ≥ 0 且 为 整 数 ,     i = 1 , 2 , . . . , 7 min\ \ \sum^{7}_{i = 1}x_i\\ s.t. = \begin{cases} x_1 + 2x_2+x_7 \geq 100\\ 3x_3 + 2x_4 + x_5 + x_7 \geq 100\\ 4x_1 + x_2 + 2x_4 + 4x_5 + 6x_6 +x_7 \geq100,\\ x_i \geq 0且为整数,\ \ \ i = 1,2,...,7 \end{cases} min  i=17xis.t.=x1+2x2+x71003x3+2x4+x5+x71004x1+x2+2x4+4x5+6x6+x7100,xi0,   i=1,2,...,7
  • 这题需要对自变量约束,其为整型
s = np.zeros((4,7))
temp = 0
for i in range(3):
    for j in range(4):
        for k in range(7):
            if (2.9 * i + 2.1 * j + k > 5.9) and (2.9 * i + 2.1 * j + k <= 6.9):
                s[:,temp] = np.array([i,j,k,6.9-(2.9 * i + 2.1 * j +k)]).T
                temp = temp + 1
ss = s[3,:][np.argsort(s[3,:])]
idx = np.argsort(s[3,:])
s = s[:,idx]
a = s[0:3,:]

# 决策变量
n = 7
# integer,变量为整型
x = cp.Variable(n,integer = True)

# 定义问题,添加约束条件
prob = cp.Problem(cp.Minimize(cp.sum(x)),
                 [a @ x >= 100,x >= 0])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最小值:", ans)
print(x.value)

输出

目标函数最小值: 91.0
[14. 43. 33.  1.  0.  0.  0.]

算法设计2

  • i = 1 , 2 , . . . , 7 i = 1,2,...,7 i=1,2,...,7分别表示套裁方案A、B、C、D、E、F、G,引进0-1变量:
    y i = { 1 ,     采 用 第 i 种 套 裁 方 法 0 ,     不 采 用 第 i 种 套 裁 方 法 y_{i} = \begin{cases} 1,\ \ \ 采用第i种套裁方法\\ 0,\ \ \ 不采用第i种套裁方法 \end{cases} yi={1,   i0,   i
  • x i ( i = 1 , 2 , . . . , 7 ) x_i(i = 1,2,...,7) xi(i=1,2,...,7)表示采用第 i i i种套裁方案下料的原材料根数。建立如下整数规划模型:
    m i n    ∑ i = 1 7 x i s . t . = { x 1 + 2 x 2 + x 7 ≥ 100 3 x 3 + 2 x 4 + x 5 + x 7 ≥ 100 4 x 1 + x 2 + 2 x 4 + 4 x 5 + 6 x 6 + x 7 ≥ 100 , x i ≥ 0 且 为 整 数 ,     i = 1 , 2 , . . . , 7 x i ≤ M y ,     i = 1 , 2 , . . . , 7 ∑ i = 1 7 y i = 3 y i = 0 或 1 ,     i = 1 , 2 , . . . , 7 min\ \ \sum^{7}_{i = 1}x_i\\ s.t. = \begin{cases} x_1 + 2x_2+x_7 \geq 100\\ 3x_3 + 2x_4 + x_5 + x_7 \geq 100\\ 4x_1 + x_2 + 2x_4 + 4x_5 + 6x_6 +x_7 \geq100,\\ x_i \geq 0且为整数,\ \ \ i = 1,2,...,7\\ x_i \leq My,\ \ \ i = 1,2,...,7\\ \sum\limits^{7}_{i = 1}y_i = 3\\ y_i = 0或1,\ \ \ i = 1,2,...,7\\ \end{cases} min  i=17xis.t.=x1+2x2+x71003x3+2x4+x5+x71004x1+x2+2x4+4x5+6x6+x7100,xi0,   i=1,2,...,7xiMy,   i=1,2,...,7i=17yi=3yi=01,   i=1,2,...,7
# 决策变量
n = 7
k = 7
# integer,变量为整型
x = cp.Variable(n,integer = True)
# boolean,变量为布尔类型
y = cp.Variable(n,boolean = True)

# 定义问题,添加约束条件
prob = cp.Problem(cp.Minimize(cp.sum(x)),
                 [a @ x >= 100,
                  x >= 0,
                  x <= 10000 * y,
                  cp.sum(y) == 3])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最小值:", ans)
print(x.value)

输出

目标函数最小值: 92.0
[15. 43. 34.  0.  0.  0.  0.]

习题2.6

  求解整数线性规划问题
m i n    z = 20 x 1 + 90 x 2 + 80 x 3 + 70 x 4 + 30 x 5 s . t . = { x 1 + x 2 + x 5 ≥ 30 x 3 + x 4 ≥ 30 3 x 1 + 2 x 3 ≤ 120 3 x 2 + 2 x 4 + x 5 ≤ 48 x j ≥ 0 且 为 整 数 ,     j = 1 , 2 , . . . . , 5 min\ \ z = 20x_1 + 90x_2 + 80x_3+70x_4+30x_5\\ s.t. = \begin{cases} x_1 + x_2 + x_5 \geq 30\\ x_3 + x_4 \geq 30\\ 3x_1 + 2x_3 \leq 120\\ 3x_2 + 2x_4+ x_5 \leq 48\\ x_j \geq 0 且为整数,\ \ \ j = 1,2,....,5 \end{cases} min  z=20x1+90x2+80x3+70x4+30x5s.t.=x1+x2+x530x3+x4303x1+2x31203x2+2x4+x548xj0,   j=1,2,....,5

算法设计

# 决策变量
n = 5
# integer,变量为整型
x = cp.Variable(n,integer = True)
# 约束1
A1 = np.array([[1,1,0,0,1],
               [0,0,1,1,0]])
b1 = np.array([30,30])
# 约束2
A2 = np.array([[3,0,2,0,0],
               [0,3,0,2,1]])
b2 = np.array([120,48])
# 定义问题,添加约束条件
c = np.array([20,90,80,70,30])
prob = cp.Problem(cp.Minimize(c.T @ x),
                 [A1 @ x >= b1,
                  A2 @ x <= b2,
                  x >= 0])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最小值:", ans)
print(x.value)

输出

目标函数最小值: 2760.0
[30.  0.  6. 24.  0.]

习题2.7

  美佳公司计划制造Ⅰ、Ⅱ两种家电产品。已知各制造一件家电时分别占用的设备A和设备B的台时,调试工序时间,每天可用于这两种家电的能力,各销售一件家电的获利情况,如表所示。问该公司应制造两种家电各多少件,使获取的利润为最大。

项目每天可用能力
设备A/h0515
设备B/h6224
调试工序/h115
利润/元21

算法设计

  • x 1 , x 2 x_{1},x_{2} x1,x2分别表示美佳公司每天制造家电Ⅰ、Ⅱ的产量,建立整数规划:
    m a x    z = 2 x 1 + x 2 s . t . = { 5 x 2 ≤ 15 6 x 1 + 2 x 2 ≤ 24 x 1 + x 2 ≤ 5 x 1 , x 2 ≥ 0   且 为 整 数 max\ \ z = 2x_1 + x_2\\ s.t. = \begin{cases} 5x_2 \leq 15 \\ 6x_1 + 2x_2 \leq 24\\ x_1 + x_2 \leq 5\\ x_1,x_2 \geq 0\ 且为整数 \end{cases} max  z=2x1+x2s.t.=5x2156x1+2x224x1+x25x1,x20 
# 决策变量
n = 2
# integer,变量为整型
x = cp.Variable(n,integer = True)
# 约束1
A1 = np.array([[0,5],
               [6,2],
               [1,1]])
b1 = np.array([15,24,5])
# 约束2
A2 = np.array([[1,0],
               [0,1]])
b2 = np.array([0,0])
# 定义问题,添加约束条件
c = np.array([2,1])
prob = cp.Problem(cp.Maximize(c.T @ x),
                 [A1 @ x <= b1,
                  A2 @ x >= b2])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最大值:", ans)
print(x.value)

输出

目标函数最大值: 8.0
[4. 0.]

习题2.8

  求解标准的指派问题,其中指派矩阵
C = [ 6 7 5 8 9 10 6 3 7 9 3 8 8 11 12 6 7 9 9 7 5 4 7 6 5 8 9 6 10 7 9 8 7 6 5 9 ] C = \begin{bmatrix} 6 & 7 & 5 & 8 & 9 & 10\\ 6 & 3 & 7 & 9 & 3 & 8\\ 8 & 11 & 12 & 6 & 7 & 9\\ 9 & 7 & 5 & 4 & 7 & 6\\ 5 & 8 & 9 & 6 & 10 & 7\\ 9 & 8 & 7 & 6 & 5 & 9\\ \end{bmatrix} C=6689597311788571259789646693771051089679

算法设计

  • C = ( c i j ) 6 × 6 C = (c_{ij})_{6 \times 6} C=(cij)6×6,引进0-1变量:
    x i j = { 1 ,     第 i 个 人 干 第 j 项 工 作 0 ,     第 i 个 人 不 干 第 j 项 工 作 x_{ij} = \begin{cases} 1,\ \ \ 第i个人干第j项工作\\ 0,\ \ \ 第i个人不干第j项工作 \end{cases} xij={1,   ij0,   ij
  • 指派问题的0-1数学模型为:
    m i n    z = ∑ i = 1 6 ∑ j = 1 6 c i j x i j s . t . = { ∑ i = 1 6 x i j = 1 ,    i = 1 , 2 , . . . , 6 ∑ i = 1 6 x i j = 1 ,    j = 1 , 2 , . . . , 6 x i j = 0 或 1. i ,    j = 1 , 2 , . . . , 6 min\ \ z = \sum^{6}_{i = 1}\sum^{6}_{j = 1}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{6}_{i = 1}x_{ij} = 1,\ \ i = 1,2,...,6\\ \sum\limits^{6}_{i = 1}x_{ij} = 1,\ \ j = 1,2,...,6\\ x_{ij} = 0或1.i,\ \ j = 1,2,...,6 \end{cases} min  z=i=16j=16cijxijs.t.=i=16xij=1,  i=1,2,...,6i=16xij=1,  j=1,2,...,6xij=01.i,  j=1,2,...,6
# 决策变量
n = (6,6)
# integer,变量为整型
x = cp.Variable(n,boolean = True)

c = np.array([[6,7,5,8,9,10],
              [6,3,7,9,3,8],
              [8,11,12,6,7,9],
              [9,7,5,4,7,6],
              [5,8,9,6,10,7],
              [9,8,7,6,5,9]])
prob = cp.Problem(cp.Minimize(cp.sum(cp.sum(cp.multiply(c,x)))),
                  [cp.sum(x,axis = 0) == 1,
                   cp.sum(x,axis = 1) == 1])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最大值:", ans)
print(x.value)

输出

目标函数最大值: 30.0
[[0. 0. 1. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 0. 0. 1.]
 [1. 0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0.]]

习题2.9

  已知某物质有8个配送中心可以供货,有15个部队用户需要该物资,配送中心和部队用户之间单位物质的运费、15个部队用户的物质需求量和8个配送中心的物质储备量数据。
  (1)根据题目给定的数据,求最小运费调用计划。
  (2)若每个配送中心,可以对某个用户配送物资,也可以不对某个用户配送物资;若配送物资,配送量要大于等于1000且小于等于2000,求此时的费用最小调用计划。

算法设计1

  • 根据题意,建立如下的夏新规划模型:
    m i n    z = ∑ i = 1 15 ∑ j = 1 8 c i j x i j s . t . = { ∑ i = 1 15 x i j ≤ b j ,    i = 1 , 2 , . . . , 8 ∑ i = 1 8 x i j = a i ,    j = 1 , 2 , . . . , 15 x i j ≥ 0 ,    i = 1 , 2 , . . . , 15    j = 1 , 2 , . . . , 6 min\ \ z = \sum^{15}_{i = 1}\sum^{8}_{j = 1}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{15}_{i = 1}x_{ij} \leq b_j,\ \ i = 1,2,...,8\\ \sum\limits^{8}_{i = 1}x_{ij} = a_i,\ \ j = 1,2,...,15\\ x_{ij} \geq 0,\ \ i = 1,2,...,15\ \ j = 1,2,...,6 \end{cases} min  z=i=115j=18cijxijs.t.=i=115xijbj,  i=1,2,...,8i=18xij=ai,  j=1,2,...,15xij0,  i=1,2,...,15  j=1,2,...,6
d = np.loadtxt("../input/math-modeling/data2_9_1.txt")
a = d[0:-1,-1]
b = d[-1,0:-1]
c = d[0:-1,0:-1]
# 决策变量
n = (15,8)
# integer,变量为整型
x = cp.Variable(n,integer = True)
prob = cp.Problem(cp.Minimize(cp.sum(cp.sum(cp.multiply(c,x)))),
                  [cp.sum(x,axis = 0) <= b,
                   cp.sum(x,axis = 1) == a,
                   x >= 0])
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最小值:", ans)
print(x.value)

输出

目标函数最小值: 9244730.0
[[   0.    0.    0.    0.    0. 3000.    0.    0.]
 [   0.    0.    0.    0. 3100.    0.    0.    0.]
 [   0.    0.    0.    0.    0.    0.    0. 2900.]
 [   0.    0. 3100.    0.    0.    0.    0.    0.]
 [3100.    0.    0.    0.    0.    0.    0.    0.]
 [   0.    0.    0. 3400.    0.    0.    0.    0.]
 [   0. 3500.    0.    0.    0.    0.    0.    0.]
 [   0.    0.    0. 3200.    0.    0.    0.    0.]
 [   0. 3000.    0.    0.    0.    0.    0.    0.]
 [   0.    0.    0.    0.    0.    0.    0. 3100.]
 [   0.    0.    0.    0.    0.    0. 3300.    0.]
 [   0.    0.    0.    0.    0.    0. 3200.    0.]
 [   0.    0.    0.    0.    0.    0. 3300.    0.]
 [   0.    0.    0.    0.    0.    0.    0. 2900.]
 [   0.    0.    0.    0.    0.    0.    0. 3100.]]

算法设计2

  • 引入0-1变量:
    y i j = { 1 ,     第 j 个 配 送 中 心 供 应 第 i 个 用 户 0 ,     第 j 个 配 送 中 心 不 供 应 第 i 个 用 户 y_{ij} = \begin{cases} 1,\ \ \ 第j个配送中心供应第i个用户\\ 0,\ \ \ 第j个配送中心不供应第i个用户 \end{cases} yij={1,   ji0,   ji
  • 建立如下的混合整数线性规划模型:
    m i n    z = ∑ i = 1 15 ∑ j = 1 8 c i j x i j s . t . = { ∑ i = 1 15 x i j ≤ b j ,    i = 1 , 2 , . . . , 8 ∑ i = 1 8 x i j = a i ,    j = 1 , 2 , . . . , 15 1000 y i j ≤ x i j ≤ 2000 y i j ,    i = 1 , 2 , . . . , 15    j = 1 , 2 , . . . , 6 y i j = 0 或 1 ,    i = 1 , 2 , . . . , 15    j = 1 , 2 , . . . , 6 min\ \ z = \sum^{15}_{i = 1}\sum^{8}_{j = 1}c_{ij}x_{ij}\\ s.t. = \begin{cases} \sum\limits^{15}_{i = 1}x_{ij} \leq b_j,\ \ i = 1,2,...,8\\ \sum\limits^{8}_{i = 1}x_{ij} = a_i,\ \ j = 1,2,...,15\\ 1000y_{ij} \leq x_{ij} \leq 2000y_{ij},\ \ i = 1,2,...,15\ \ j = 1,2,...,6\\ y_{ij} = 0或1,\ \ i = 1,2,...,15\ \ j = 1,2,...,6\\ \end{cases} min  z=i=115j=18cijxijs.t.=i=115xijbj,  i=1,2,...,8i=18xij=ai,  j=1,2,...,151000yijxij2000yij,  i=1,2,...,15  j=1,2,...,6yij=01,  i=1,2,...,15  j=1,2,...,6
    输出
目标函数最小值: 12682750.0
[[   0.    0.    0.    0. 1000. 2000.    0.    0.]
 [   0.    0.    0.    0. 2000. 1100.    0.    0.]
 [   0.    0. 1000.    0.    0.    0.    0. 1900.]
 [   0.    0. 2000.    0. 1100.    0.    0.    0.]
 [2000.    0.    0. 1100.    0.    0.    0.    0.]
 [1400.    0.    0. 2000.    0.    0.    0.    0.]
 [1500. 2000.    0.    0.    0.    0.    0.    0.]
 [   0.    0.    0. 2000. 1200.    0.    0.    0.]
 [1000. 2000.    0.    0.    0.    0.    0.    0.]
 [   0.    0. 1100.    0.    0.    0.    0. 2000.]
 [   0.    0.    0.    0.    0.    0. 2000. 1300.]
 [   0.    0.    0. 1200.    0.    0. 2000.    0.]
 [   0.    0.    0. 1300.    0.    0. 2000.    0.]
 [   0.    0. 1000.    0.    0.    0.    0. 1900.]
 [   0.    0.    0. 1100.    0.    0.    0. 2000.]]

习题2.10

  有4名同学到一家公司参加3个阶段的面试:公司要求每个同学都必须首先找公司秘书初试,然后到部门主管处复试,最后到经理处参加面试,并且不允许插队(即任何一个阶段4名同学的顺序是一样的)。由于4名同学的专业背景不同,所以每人在3个阶段的面试时间也不同,如下表所示。这4名同学约定他们全部面试完以后一起离开公司。假定现在时间是早餐8:00,请问他们最早何时能离开公司?

同学秘书初试主管复试经理面试
同学甲141621
同学乙191710
同学丙101512
同学丁91213

算法设计

  • t i j t_{ij} tij为第 i i i名同学参加第 j j j阶段面试需要的时间,令 x i j x_{ij} xij表示第 i i i名同学参加第 j j j阶段面试的开始时间, T T T为完成全部面试所花费的时间。引进0-1变量:
    y i k = { 1 ,     第 i 名 同 学 在 第 k 名 同 学 前 面 面 试 0 ,     第 k 名 同 学 在 第 i 名 同 学 前 面 面 试 y_{ik} = \begin{cases} 1,\ \ \ 第i名同学在第k名同学前面面试\\ 0,\ \ \ 第k名同学在第i名同学前面面试 \end{cases} yik={1,   ik0,   ki
  • 由此建立如下的混合整数规划模型:
    m i n    T s . t . = { T ≥ x i 3 + t i 3 ,    i = 1 , 2 , 3 , 4 x i j + t i j ≤ x i , j + 1 ,    i = 1 , 2 , 3 , 4 ;    j = 1 , 2 x i j + t i j ≤ x k j + 10000 ( 1 − y i k ) ,    1 ≤ i < k ≤ 4 ;    j = 1 , 2 , 3 x k j + t k j ≤ x i j + 10000 y i k ,    1 ≤ i < k ≤ 4 ;    j = 1 , 2 , 3 y i k = 0 或 1 ,    1 ≤ i < k ≤ 4 min\ \ T\\ s.t. = \begin{cases} T \geq x_{i3} + t_{i3},\ \ i = 1,2,3,4\\ x_{ij} + t_{ij} \leq x_{i,j+1},\ \ i = 1,2,3,4;\ \ j=1,2\\ x_{ij} + t_{ij} \leq x_{kj} + 10000(1-y_{ik}),\ \ 1 \leq i < k \leq 4;\ \ j = 1,2,3\\ x_{kj} + t_{kj} \leq x_{ij} + 10000y_{ik},\ \ 1 \leq i < k \leq 4;\ \ j = 1,2,3\\ y_{ik} = 0或1,\ \ 1 \leq i < k \leq 4 \end{cases} min  Ts.t.=Txi3+ti3,  i=1,2,3,4xij+tijxi,j+1,  i=1,2,3,4;  j=1,2xij+tijxkj+10000(1yik),  1i<k4;  j=1,2,3xkj+tkjxij+10000yik,  1i<k4;  j=1,2,3yik=01,  1i<k4
  • 对于大量有循环约束,可以在Python中定义一个列表,然后使用for循环来追加或扩展约束
t = np.array([[14,16,21],
             [19,17,10],
             [10,15,12],
             [9,12,13]])
x = cp.Variable((4,3),nonneg = True)
y = cp.Variable((4,4),boolean = True)
T = cp.Variable(1)
constraints = [x[:,2] + t[:,2] <= T]
for i in range(4):
    for j in range(2):
         constraints += [x[i,j] + t[i,j] <= x[i,j+1]]
for i in range(3):
    for j in range(3):
        for k in range(i+1,4):
            constraints += [x[i,j] + t[i,j] <= x[k,j] + 10000 * (1-y[i,k]),
                            x[k,j] + t[k,j] <= x[i,j] + 10000 * y[i,k]]
prob = cp.Problem(cp.Minimize(T),constraints)
# 求解
ans = prob.solve(solver='GLPK_MI')
# 输出结果
print("目标函数最小值:", ans)
print(x.value)

输出

目标函数最小值: 82.0
[[ 9. 23. 39.]
 [33. 54. 72.]
 [23. 39. 60.]
 [-0.  9. 21.]]
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐