【数学建模】 函数极值与规划模型

news2025/2/28 15:54:01

文章目录

  • 函数极值与规划模型
    • 1. 线性代数和线性规划的联系
      • 1.1 线性代数的基本概念
      • 1.2 线性规划的基本概念
      • 1.3 线性代数与线性规划的联系
        • 矩阵和向量
        • 线性方程组
        • 单纯形法
        • 内点法
        • 凸优化
      • 1.4 例子
    • 2. Numpy有关矩阵运算示例
      • 2.1 矩阵的创建
      • 2.2 矩阵的基本运算
      • 2.3 矩阵的合并
      • 2.4 矩阵的分割
    • 3. 线性规划工具包介绍
      • 3.1 scipy的linprog函数
        • 示例代码
      • 3.2 PuLP工具包
        • 安装PuLP
        • 使用示例
        • 参数说明
    • 4. 线性规划的建模案例
      • 4.1 油料的采购与加工计划
        • 实现这个问题的代码如下:
        • 代码详细解释
        • 结果解释
      • 4.2 农民承包土地问题
        • 模型建立
        • 决策变量
        • 目标函数
        • 约束条件
        • 代码实现
        • 参数解释
        • 计算结果
        • 补充pulp工具包的解题代码
    • 5. 非线性规划工具包介绍
      • 5.1 SciPy的`minimize`函数
        • 安装SciPy
        • 使用示例
        • 参数说明
        • 返回值
      • 5.2 Pyomo
        • 安装Pyomo
        • 使用示例
        • 参数说明
        • 返回值
      • 5.3 IPOPT
        • 安装IPOPT
        • 使用示例
      • 5.4 CVXPY
        • 安装CVXPY
        • 使用示例
        • 参数说明
        • 返回值
      • 5.5 各类工具包对比
    • 6. 非线性规划的建模案例
    • 7. 整数规划与指派问题
      • 7.1 整数规划的基本概念
      • 7.2 分支定界法
      • 7.3 指派问题与匈牙利法
    • 8. 一些拓展
      • 8.1 动态规划与贪心算法
      • 8.2 博弈论与排队论
      • 8.3 多目标规划
      • 8.4 Monte Carlo模拟
    • 9. 一些奇奇怪怪的知识点
      • 9.1 半正定矩阵和正定矩阵分别是什么,两者有什么联系和区别
        • 基本概念
        • 联系与区别
        • 总结
      • 9.2 线性函数和非线性函数的区别
        • 定义和基本形式
        • 超位性和齐次性
        • 求解方法
        • 实际应用
      • 9.3 分支定界法的时间复杂度
        • 分支定界法的时间复杂度因素
        • 指数级复杂度的原因
        • 剪枝的影响
        • 复杂度示例
    • 10. 学习心得

函数极值与规划模型

1. 线性代数和线性规划的联系

1.1 线性代数的基本概念

线性代数是数学的一个分支,主要研究向量、向量空间(或线性空间)、线性变换以及线性方程组。它提供了用于描述和操作线性系统的工具。以下是一些线性代数的基本概念:

  • 向量:具有方向和大小的量,可以表示为一维数组。
  • 矩阵:矩阵是由向量组成的二维数组,用于表示线性变换和线性方程组。
  • 线性方程组:由多个线性方程组成的方程组,可以用矩阵形式表示。
  • 行列式:矩阵的一个标量值属性,反映了矩阵的一些几何性质,如是否可逆。
  • 特征值和特征向量:矩阵的一些固有属性,反映了线性变换的一些重要性质。

1.2 线性规划的基本概念

线性规划是一种优化技术,旨在最大化或最小化一个线性目标函数,同时满足一组线性约束条件。以下是线性规划的基本概念:

  • 目标函数:需要优化的线性函数,通常表示为 (c^T x),其中 (c) 是系数向量,(x) 是决策变量向量。
  • 约束条件:限制决策变量的线性不等式或等式,通常表示为 (Ax \leq b) 或 (Ax = b),其中 (A) 是系数矩阵,(b) 是常数向量。
  • 可行解空间:满足所有约束条件的决策变量的集合。
  • 最优解:在可行解空间中使目标函数达到最大或最小值的解。

1.3 线性代数与线性规划的联系

矩阵和向量

在线性规划中,决策变量和约束条件通常用向量和矩阵表示。例如,目标函数 (c^T x) 和约束条件 (Ax \leq b) 都使用了线性代数中的矩阵和向量表示法。这使得线性规划问题可以形式化为矩阵运算问题,从而利用线性代数的方法来分析和求解。

线性方程组

线性规划中的约束条件通常包括线性方程组或线性不等式组。解决这些方程组和不等式组是线性规划的核心任务之一。线性代数提供了求解线性方程组的工具,如高斯消元法和矩阵分解方法。

单纯形法

单纯形法是一种用于求解线性规划问题的算法,基于线性代数的基本原理。它通过在约束条件定义的多面体(可行解空间)的顶点之间移动,逐步寻找最优解。这个过程涉及大量的矩阵运算和线性代数操作,如矩阵的行变换和基变换。

内点法

内点法是另一种解决线性规划问题的算法,它通过在可行解空间内部寻找路径来逼近最优解。内点法使用了线性代数中的矩阵分解和求解技术,以有效地处理大规模的线性规划问题。

凸优化

线性规划是凸优化的一种特例。线性规划问题的可行解空间是一个凸多面体,而线性代数提供了分析凸集和凸函数的工具。这些工具对于理解线性规划的几何性质和设计求解算法非常重要。

1.4 例子

以下是一个简单的线性规划问题,展示了如何使用线性代数方法来求解:

问题
最大化 z = 3 x 1 + 2 x 2 z = 3x_1 + 2x_2 z=3x1+2x2

约束条件:
{ 2 x 1 + x 2 ≤ 20 4 x 1 − 5 x 2 ≥ − 10 x 1 + 2 x 2 ≤ 15 x 1 , x 2 ≥ 0 \begin{cases} 2x_1 + x_2 \leq 20 \\ 4x_1 - 5x_2 \geq -10 \\ x_1 + 2x_2 \leq 15 \\ x_1, x_2 \geq 0 \end{cases} 2x1+x2204x15x210x1+2x215x1,x20

步骤

  1. 将约束条件转换为标准形式:
    { 2 x 1 + x 2 ≤ 20 4 x 1 − 5 x 2 ≤ 10 x 1 + 2 x 2 ≤ 15 x 1 , x 2 ≥ 0 \begin{cases} 2x_1 + x_2 \leq 20 \\ 4x_1 - 5x_2 \leq 10 \\ x_1 + 2x_2 \leq 15 \\ x_1, x_2 \geq 0 \end{cases} 2x1+x2204x15x210x1+2x215x1,x20
  2. 使用线性代数方法(如单纯形法或内点法)求解。

2. Numpy有关矩阵运算示例

直接上代码:

2.1 矩阵的创建

# 创建数组
    a = np.array([1,2,3])

    # 指定数据类型
    a = np.array([1,2,3],dtype=np.int64)

    # 创建二维数组
    a = np.array([[1,2,3],[4,5,6]])

    # 创建多维数组
    a = np.array([[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]],[[1,2,3],[4,5,6]]]) # 3x2x3
    print(a.shape)

    # 创建数据全为0
    a = np.zeros((1,3))

    # 创建数据全为1
    a = np.ones((1,3))

    # 创建数据接近0
    a = np.empty((1,3))

    # 创建一个从10到20的数组,步长为1
    a = np.arange(10, 20, 1)
    print("数组 a:", a)

    # 创建一个从10到20的数组,步长为2
    b = np.arange(10, 20, 2)
    print("数组 b:", b)

    # 创建一个从10到20的数组,包含5个均匀分布的点
    c = np.linspace(10, 20, 5)
    print("数组 c:", c)

    # 创建一个从10到20的数组,包含10个均匀分布的点
    d = np.linspace(10, 20, 10)
    print("数组 d:", d)

    # 生成 3x2 的随机数数组
    # 指定范围
    low = 10
    high = 20
    random_array = np.random.uniform(low, high, (3, 2))
    print("3x2 的随机数数组:\n", random_array)

    # 生成 3x2 的随机整数数组
    random_int_array = np.random.randint(low, high, (3, 2))
    print("3x2 的随机整数数组:\n", random_int_array)

2.2 矩阵的基本运算

# 创建两个 3x2 的矩阵
A = np.array([[1, 2], [3, 4], [5, 6]])
B = np.array([[6, 5], [4, 3], [2, 1]])

print("矩阵 A:\n", A)
print("矩阵 B:\n", B)

# 矩阵加法
C = A + B
print("矩阵 A + B:\n", C)

# 矩阵减法
D = A - B
print("矩阵 A - B:\n", D)

# 矩阵乘法(元素乘法)
E = A * B
print("矩阵 A * B (元素乘法):\n", E)

# 矩阵点乘
F = A.dot(B.T)
print("矩阵 A 和 B.T 的点乘:\n", F)

# 矩阵转置
A_T = A.T
print("矩阵 A 的转置:\n", A_T)

2.3 矩阵的合并

# 创建一个 2x2 方阵
G = np.array([[1, 2], [3, 4]])
G_inv = np.linalg.inv(G)
print("矩阵 G:\n", G)
print("矩阵 G 的逆:\n", G_inv)

# 垂直合并
H = np.vstack((A, B))
print("垂直合并 A 和 B:\n", H)

# 水平合并
I = np.hstack((A, B))
print("水平合并 A 和 B:\n", I)

2.4 矩阵的分割

# 垂直分割
J1, J2, J3 = np.vsplit(A, 3)
print("垂直分割 A:\n", J1, "\n", J2, "\n", J3)

# 水平分割
K1, K2 = np.hsplit(A, 2)
print("水平分割 A:\n", K1, "\n", K2)

3. 线性规划工具包介绍

  • scipy.optimize.linprog 是一个简单易用的函数,适用于基本的线性规划问题。
  • PuLP 提供了更强大的功能和灵活性,适用于复杂的线性规划问题。

下面是两者的详细介绍和使用示例

3.1 scipy的linprog函数

res=linprog(c=c, A_ub=A, b_ub=b, A_eq=aeq, b_eq=beq, bounds=bounds)

参数说明

  • c: 目标函数的系数向量。我们希望最小化目标函数 (c \cdot x)。
  • A_ub: 不等式约束矩阵(小于等于)。每一行代表一个不等式约束的系数。
  • b_ub: 不等式约束向量。每个元素代表对应不等式约束的右侧常数。
  • A_eq: 等式约束矩阵。每一行代表一个等式约束的系数。
  • b_eq: 等式约束向量。每个元素代表对应等式约束的右侧常数。
  • bounds: 变量的取值范围。每个元组表示一个变量的下限和上限。

返回值

  • res: 返回一个优化结果对象,其中包含以下属性:
    • x: 最优解。
    • fun: 目标函数在最优解处的值。
    • success: 优化是否成功的布尔值。
    • status: 优化的状态代码。
    • message: 描述优化状态的消息。
示例代码

问题描述:

最大化目标函数:
z = − x 1 + 4 x 2 z = -x_1 + 4x_2 z=x1+4x2

约束条件:
{ − 3 x 1 + x 2 ≤ 6 x 1 + 2 x 2 ≤ 4 2 x 1 + x 2 = 1 x 1 , x 2 ≥ 0 \begin{cases} -3x_1 + x_2 \leq 6 \\ x_1 + 2x_2 \leq 4 \\ 2x_1 + x_2 = 1 \\ x_1, x_2 \geq 0 \end{cases} 3x1+x26x1+2x242x1+x2=1x1,x20

转换为标准形式进行求解:

import numpy as np
from scipy.optimize import linprog

# 定义目标函数的系数向量
c = [-1, 4]  # 原目标函数是最大化 -x1 + 4x2,但 linprog 求解的是最小化问题

# 定义不等式约束矩阵和向量
A_ub = [[-3, 1], [1, 2]]
b_ub = [6, 4]

# 定义等式约束矩阵和向量
A_eq = [[2, 1]]
b_eq = [1]

# 定义变量的取值范围
x0_bounds = (0, None)
x1_bounds = (0, None)

# 调用 linprog 函数求解
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=[x0_bounds, x1_bounds])

# 打印结果
print('Optimal value:', res.fun, '\nX:', res.x)

3.2 PuLP工具包

PuLP 是一个用于线性规划的 Python 库,它提供了定义和求解线性规划问题的简单接口。与 scipy.optimize.linprog 相比,PuLP 更加灵活,适用于更复杂的线性规划问题。

安装PuLP

可以使用以下命令安装 PuLP:

pip install pulp
使用示例

问题描述:

最小化目标函数:
z = x 1 + 4 x 2 z = x_1 + 4x_2 z=x1+4x2

约束条件:
{ − 3 x 1 + x 2 ≤ 6 x 1 + 2 x 2 ≤ 4 2 x 1 + x 2 = 1 x 1 , x 2 ≥ 0 \begin{cases} -3x_1 + x_2 \leq 6 \\ x_1 + 2x_2 \leq 4 \\ 2x_1 + x_2 = 1 \\ x_1, x_2 \geq 0 \end{cases} 3x1+x26x1+2x242x1+x2=1x1,x20

转换为标准形式进行求解:

import pulp

# 创建一个最小化问题
model = pulp.LpProblem("Minimize Problem", pulp.LpMinimize)

# 定义变量
x1 = pulp.LpVariable('x1', lowBound=0)  # x1 >= 0
x2 = pulp.LpVariable('x2', lowBound=0)  # x2 >= 0

# 定义目标函数
model += x1 + 4 * x2, "Objective Function"

# 定义约束条件
model += -3 * x1 + x2 <= 6, "Constraint 1"
model += x1 + 2 * x2 <= 4, "Constraint 2"
model += 2 * x1 + x2 == 1, "Constraint 3"

# 求解问题
model.solve()

# 输出结果
print("Status:", pulp.LpStatus[model.status])
print("Optimal value of x1:", x1.varValue)
print("Optimal value of x2:", x2.varValue)
print("Optimal value of the objective function:", pulp.value(model.objective))
参数说明
  • pulp.LpProblem: 创建一个线性规划问题,可以指定问题名称和类型(最小化或最大化)。
  • pulp.LpVariable: 定义决策变量,可以指定变量名和范围。
  • +=: 添加目标函数或约束条件。
  • model.solve(): 求解线性规划问题。
  • pulp.LpStatus: 返回求解状态。
  • varValue: 返回变量的最优解值。
  • pulp.value: 返回目标函数在最优解处的值。

4. 线性规划的建模案例

4.1 油料的采购与加工计划

某加工厂加工一种油,原料为五种油(植物油1、植物油2、非植物油1、非植物油2、非植物油3),每种油的价格和硬度如图表所示。最终生产的成品将以150英镑/吨的价格卖出。每个月能够提炼的植物油不超过200吨,非植物油不超过250吨。假设提炼过程中油料没有损失,提炼费用忽略不计,并且最终的产品的硬度需要在(3-6)之间(假设硬度的混合时线性的)。根据以上信息,制定月采购和加工计划。

假设 x 1 , x 2 , x 3 , x 4 , x 5 x_1, x_2, x_3, x_4, x_5 x1,x2,x3,x4,x5 分别为每月需要采购的原料油吨数, x 6 x_6 x6 为每个月加工的成品油吨数,由于不考虑油料损失,存在关系:

x 6 = x 1 + x 2 + x 3 + x 4 + x 5 (3.4.2) x_6 = x_1 + x_2 + x_3 + x_4 + x_5 \tag{3.4.2} x6=x1+x2+x3+x4+x5(3.4.2)

平均的硬度为:

η = ∑ i = 1 5 w i x i x 6 (3.4.3) \eta = \frac{\sum_{i=1}^{5} w_i x_i}{x_6} \tag{3.4.3} η=x6i=15wixi(3.4.3)

加上植物油重量限制和非植物油重量限制,根据题意,可以列出规划模型如下:

minimize  z = − 110 x 1 − 120 x 2 − 130 x 3 − 110 x 4 − 115 x 5 + 150 x 6 s.t.  x 1 + x 2 ≤ 200 x 3 + x 4 + x 5 ≤ 250 8.8 x 1 + 6.1 x 2 + 2.0 x 3 + 4.2 x 4 + 5.0 x 5 ≤ 6 x 6 8.8 x 1 + 6.1 x 2 + 2.0 x 3 + 4.2 x 4 + 5.0 x 5 ≥ 3 x 6 x 1 + x 2 + x 3 + x 4 + x 5 = x 6 x i ≥ 0 , i = 1 , 2 , … , 6 (3.4.4) \begin{align} \text{minimize}~& z = -110x_1 - 120x_2 - 130x_3 - 110x_4 - 115x_5 + 150x_6 \\[0.5em] \text{s.t.}~ & x_1 + x_2 \leq 200 \\ & x_3 + x_4 + x_5 \leq 250 \\ & 8.8x_1 + 6.1x_2 + 2.0x_3 + 4.2x_4 + 5.0x_5 \leq 6x_6 \\ & 8.8x_1 + 6.1x_2 + 2.0x_3 + 4.2x_4 + 5.0x_5 \geq 3x_6 \\ & x_1 + x_2 + x_3 + x_4 + x_5 = x_6 \\ & x_i \geq 0, \quad i = 1, 2, \dots, 6 \end{align} \tag{3.4.4} minimize s.t. z=110x1120x2130x3110x4115x5+150x6x1+x2200x3+x4+x52508.8x1+6.1x2+2.0x3+4.2x4+5.0x56x68.8x1+6.1x2+2.0x3+4.2x4+5.0x53x6x1+x2+x3+x4+x5=x6xi0,i=1,2,,6(3.4.4)

实现这个问题的代码如下:
from scipy.optimize import linprog

# 定义目标函数系数
c = [110, 120, 130, 110, 115, -150]

# 定义不等式约束矩阵
A = [
    [1, 1, 0, 0, 0, 0],             # 植物油重量限制
    [0, 0, 1, 1, 1, 0],             # 非植物油重量限制
    [8.8, 6.1, 2.0, 4.2, 5.0, -6],  # 硬度上限
    [-8.8, -6.1, -2.0, -4.2, -5.0, 3]  # 硬度下限
]

# 定义不等式约束右侧常数
b = [200, 250, 0, 0]

# 定义等式约束矩阵
aeq = [[1, 1, 1, 1, 1, -1]]  # 总重量等于成品油重量

# 定义等式约束右侧常数
beq = [0]

# 定义变量的取值范围
bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, 450)]

# 求解线性规划问题
res = linprog(c=c, A_ub=A, b_ub=b, A_eq=aeq, b_eq=beq, bounds=bounds)

# 打印结果
print(f'Optimal solution: {res.x}')
print(f'Maximum profit: {-res.fun}')  # 由于目标函数是取负,因此要取反得到最大利润
代码详细解释
  1. 定义目标函数系数

    • c = [110, 120, 130, 110, 115, -150]:目标函数的系数,其中最后一项 x 6 x_6 x6 的系数是 -150(因为我们要最大化利润,因此在求解时使用负号)。
  2. 定义不等式约束矩阵

    • A = [...]:包含四个不等式约束:
      • [1, 1, 0, 0, 0, 0]:植物油重量限制 x 1 + x 2 ≤ 200 x_1 + x_2 \leq 200 x1+x2200
      • [0, 0, 1, 1, 1, 0]:非植物油重量限制 x 3 + x 4 + x 5 ≤ 250 x_3 + x_4 + x_5 \leq 250 x3+x4+x5250
      • [8.8, 6.1, 2.0, 4.2, 5.0, -6]:硬度上限 8.8 x 1 + 6.1 x 2 + 2.0 x 3 + 4.2 x 4 + 5.0 x 5 ≤ 6 x 6 8.8x_1 + 6.1x_2 + 2.0x_3 + 4.2x_4 + 5.0x_5 \leq 6x_6 8.8x1+6.1x2+2.0x3+4.2x4+5.0x56x6
      • [-8.8, -6.1, -2.0, -4.2, -5.0, 3]:硬度下限 8.8 x 1 + 6.1 x 2 + 2.0 x 3 + 4.2 x 4 + 5.0 x 5 ≥ 3 x 6 8.8x_1 + 6.1x_2 + 2.0x_3 + 4.2x_4 + 5.0x_5 \geq 3x_6 8.8x1+6.1x2+2.0x3+4.2x4+5.0x53x6
  3. 定义不等式约束右侧常数

    • b = [200, 250, 0, 0]:对应四个不等式约束的右侧常数。
  4. 定义等式约束矩阵

    • aeq = [[1, 1, 1, 1, 1, -1]]:总重量等于成品油重量 x 1 + x 2 + x 3 + x 4 + x 5 = x 6 x_1 + x_2 + x_3 + x_4 + x_5 = x_6 x1+x2+x3+x4+x5=x6
  5. 定义等式约束右侧常数

    • beq = [0]:等式约束右侧常数。
  6. 定义变量的取值范围

    • bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, 450)]:定义各变量的取值范围,所有 x i x_i xi 非负,其中 x 6 x_6 x6 上限为 450。
  7. 求解线性规划问题

    • 使用 linprog 函数求解线性规划问题,返回结果 res
  8. 打印结果

    • print(f'Optimal solution: {res.x}'):打印最优解,即各油料采购量。
    • print(f'Maximum profit: {-res.fun}'):打印最大利润(取负号)。
结果解释

代码执行后,五种原料油的采购量分别为 [159.25, 40.7407, 0, 250, 0] 吨,此时总利润可以达到最大,约为 17592 英镑/月。这展示了通过线性规划方法优化采购和加工计划,以实现利润最大化的过程。

4.2 农民承包土地问题

一个农民承包了6块耕地共300亩,准备播种小麦、玉米、水果和蔬菜四种农产品,各种农产品的计划播种面积、每块土地种植不同农产品的单产收益如下表:
在这里插入图片描述

问如何安排种植计划,可得到最大收益。

这是一个产销平衡的运输问题。可以建立下列的运输模型:
在这里插入图片描述

对上面问题建立模型,并且给出代码

要解决这个农民的种植计划问题,我们可以将其视为一个线性规划问题,目标是最大化收益。在这个问题中,我们有以下信息:

  1. 每块地的面积和各块地的面积总和。
  2. 每块地种植不同作物的收益。
  3. 每种作物的计划种植面积。

基于这些信息,我们可以建立线性规划模型。设 x i j x_{ij} xij 表示在地块 i i i 上种植作物 j j j 的面积,目标是最大化总收益。

模型建立
决策变量

x i j x_{ij} xij 表示在种植作物 i i i 在地块 j j j的种植面积,其中 i = 1 , 2 , … , 4 i = 1, 2, \ldots, 4 i=1,2,,4 分别表示小麦、玉米、水果和蔬菜, j = 1 , 2 , … , 6 j = 1, 2, \ldots, 6 j=1,2,,6 表示地块。

目标函数

最大化总收益:

max  Z = ∑ i = 1 4 ∑ j = 1 6 p i j x i j \text{max } Z = \sum_{i=1}^{4} \sum_{j=1}^{6} p_{ij} x_{ij} max Z=i=14j=16pijxij

其中, p i j p_{ij} pij 表示种植作物 i i i 在地块 i i i 上的单产收益。

约束条件
  1. 每块地的面积约束:

∑ i = 1 4 x i j ≤ 地块  j  的面积 , j = 1 , 2 , … , 6 \sum_{i=1}^{4} x_{ij} \leq \text{地块 }j\text{ 的面积}, \quad j = 1, 2, \ldots, 6 i=14xij地块 j 的面积,j=1,2,,6

  1. 每种作物的种植面积约束:

∑ j = 1 6 x i j = 作物  i  的计划种植面积 , i = 1 , 2 , 3 , 4 \sum_{j=1}^{6} x_{ij} = \text{作物 }i\text{ 的计划种植面积}, \quad i = 1, 2, 3, 4 j=16xij=作物 i 的计划种植面积,i=1,2,3,4

  1. 非负约束:

x i j ≥ 0 , ∀ i , j x_{ij} \geq 0, \quad \forall i, j xij0,i,j

代码实现

以下是使用 scipy.optimize.linprog 来求解该问题的代码:

from scipy.optimize import linprog
import numpy as np

# 定义单产收益矩阵 p_ij
    p = np.array([
        [500, 800, 1000, 1200],
        [550, 700, 960, 1040],
        [630, 600, 840, 980],
        [1000, 950, 650, 860],
        [800, 900, 600, 880],
        [700, 930, 700, 780]
    ]).T

    # 地块面积
    land_area = np.array([42, 56, 44, 39, 60, 59])

    # 作物计划种植面积
    crop_area = np.array([76, 88, 96, 40])

    # 将收益矩阵展平
    c = -p.flatten()

    # 不等式约束:每块地的总种植面积不超过其面积
    A_ub = np.zeros((6, 24))
    for j in range(6):
        A_ub[j,j::6] = 1

    b_ub = land_area

    # 等式约束:每种作物的总种植面积等于其计划面积
    A_eq = np.zeros((4, 24))
    for i in range(4):
        A_eq[i, i * 6:(i + 1) * 6] = 1

    b_eq = crop_area

    # 变量范围
    bounds = [(0, None) for _ in range(24)]

    # 求解线性规划问题
    res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs')

    # 结果展示
    if res.success:
        x = res.x.reshape((4, 6))
        print("最优种植计划 (每块地种植的面积):")
        print(x)
        print(f"最大收益: {-res.fun}")
    else:
        print("未找到最优解")
参数解释
  • c: 目标函数的系数向量,包含所有地块和作物组合的收益(取负号是因为 linprog 默认最小化)。
  • A_ub: 不等式约束矩阵,每行对应一个地块,每列对应一个组合。
  • b_ub: 不等式约束的右侧常数,每个元素对应地块的面积。
  • A_eq: 等式约束矩阵,每行对应一个作物,每列对应一个组合。
  • b_eq: 等式约束的右侧常数,每个元素对应作物的计划种植面积。
  • bounds: 决策变量的范围,每个变量的取值范围为 [0, ∞)。

该代码通过求解线性规划模型来确定每块地应种植的作物面积,以实现最大收益。

计算结果
最优种植计划 (每块地种植的面积):
[[ 0.  0.  6. 39. 31.  0.]
 [ 0.  0.  0.  0. 29. 59.]
 [ 2. 56. 38.  0.  0.  0.]
 [40.  0.  0.  0.  0.  0.]]
最大收益: 284230.0

补充pulp工具包的解题代码
import pulp
import numpy as np
def transportation_problem(costs, x_max, y_max):
    row = len(costs)
    col = len(costs[0])
    prob = pulp.LpProblem('Transportation Proble',sense=pulp.LpMaximize)
    var = [[pulp.LpVariable(f'x{i}{j}',lowBound=0,cat=pulp.LpInteger) for j in range(col)] for i in range(row)]

    # 转为一维

    flatten = lambda x:[y for l in x for y in flatten(l)] if type(x) is list else [x]
    prob += pulp.lpDot(flatten(var),costs.flatten())
    for i in range(row):
        prob += (pulp.lpSum(var[i]) <= x_max[i])
    for j in range(col):
        prob += (pulp.lpSum([var[i][j] for i in range(row)]) <= y_max[j])
    prob.solve()
    return {'objective':pulp.value(prob.objective),'var':[[pulp.value(var[i][j]) for j in range(col)] for i in range(row)]}
costs = np.array([[500,550,630,1000,800,700],
                [800,700,600,950,900,930],
                [1000,960,840,650,600,700],
                [1200,1040,980,860,880,780]])
max_plant = [76,88,96,40]
max_cultivation = [42,56,44,39,60,59]
res = transportation_problem(costs, max_plant, max_cultivation)
print(f'最大值为{res["objective"]}')
print("各个变量的取值为:")
print(res['var'])
# 最大值为284230.0
# 各变量的取值为:
# [[0.0, 0.0, 6.0, 39.0, 31.0, 0.0],
#  [0.0, 0.0, 0.0, 0.0, 29.0, 59.0],
#  [2.0, 56.0, 38.0, 0.0, 0.0, 0.0],
#  [40.0, 0.0, 0.0, 0.0, 0.0, 0.0]]

5. 非线性规划工具包介绍

非线性规划(Nonlinear Programming,NLP)涉及优化非线性目标函数,同时满足一组非线性约束。由于非线性问题的复杂性,相较于线性规划,求解非线性规划问题的方法更多样且更复杂。以下是一些常用的非线性规划工具包及其详细内容:

5.1 SciPy的minimize函数

SciPy 库中的 minimize 函数是一个通用的优化器,适用于多种优化问题,包括无约束和有约束的非线性规划问题。

安装SciPy
pip install scipy
使用示例

问题描述:

最小化目标函数:
f ( x , y ) = ( x − 1 ) 2 + ( y − 2 ) 2 f(x, y) = (x - 1)^2 + (y - 2)^2 f(x,y)=(x1)2+(y2)2

约束条件:
{ x 2 + y 2 ≤ 1 x + y = 1 \begin{cases} x^2 + y^2 \leq 1 \\ x + y = 1 \end{cases} {x2+y21x+y=1

import numpy as np
from scipy.optimize import minimize

# 定义目标函数
def objective(x):
    return (x[0] - 1)**2 + (x[1] - 2)**2

# 定义约束条件
def constraint1(x):
    return x[0]**2 + x[1]**2 - 1

def constraint2(x):
    return x[0] + x[1] - 1

# 初始猜测
x0 = [0.5, 0.5]

# 定义约束
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'eq', 'fun': constraint2}
cons = [con1, con2]

# 定义变量的取值范围
bnds = [(0, None), (0, None)]

# 使用 minimize 函数求解
solution = minimize(objective, x0, method='SLSQP', bounds=bnds, constraints=cons)

# 打印结果
print('Optimal value:', solution.fun)
print('Optimal solution:', solution.x)
参数说明
  • objective: 目标函数。
  • x0: 初始猜测。
  • method: 优化算法(例如,SLSQPtrust-constr等)。
  • bounds: 变量的取值范围。
  • constraints: 约束条件。
返回值
  • solution: 包含优化结果的对象,属性包括 fun(目标函数值)、x(最优解)等。

5.2 Pyomo

Pyomo 是一个强大的 Python 库,用于定义和求解各种优化问题,包括线性规划、非线性规划、混合整数规划等。

安装Pyomo
pip install pyomo
使用示例

问题描述:

最小化目标函数:
f ( x , y ) = ( x − 1 ) 2 + ( y − 2 ) 2 f(x, y) = (x - 1)^2 + (y - 2)^2 f(x,y)=(x1)2+(y2)2

约束条件:
{ x 2 + y 2 ≤ 1 x + y = 1 \begin{cases} x^2 + y^2 \leq 1 \\ x + y = 1 \end{cases} {x2+y21x+y=1

from pyomo.environ import ConcreteModel, Var, Objective, Constraint, SolverFactory

# 创建模型
model = ConcreteModel()

# 定义变量
model.x = Var(bounds=(0, None))
model.y = Var(bounds=(0, None))

# 定义目标函数
model.obj = Objective(expr=(model.x - 1)**2 + (model.y - 2)**2, sense=1)

# 定义约束条件
model.con1 = Constraint(expr=model.x**2 + model.y**2 <= 1)
model.con2 = Constraint(expr=model.x + model.y == 1)

# 求解模型
solver = SolverFactory('ipopt')
solver.solve(model)

# 打印结果
print('Optimal value:', model.obj())
print('Optimal solution: x =', model.x(), ', y =', model.y())
参数说明
  • ConcreteModel: 创建一个具体模型实例。
  • Var: 定义变量。
  • Objective: 定义目标函数。
  • Constraint: 定义约束条件。
  • SolverFactory: 指定求解器。
返回值
  • model.obj(): 目标函数在最优解处的值。
  • model.x(), model.y(): 变量的最优解值。

5.3 IPOPT

IPOPT(Interior Point OPTimizer)是一个用于大规模非线性优化的求解器,特别适合处理具有非线性约束的问题。

安装IPOPT

IPOPT 通常与 Pyomo 一起使用,安装命令如下:

pip install ipopt

然后,需要单独下载并安装 IPOPT 可执行文件,并将其路径添加到系统路径中。

使用示例

上面的 Pyomo 示例已经展示了如何使用 IPOPT 求解非线性规划问题。只需在求解器部分指定 ipopt 即可:

solver = SolverFactory('ipopt')
solver.solve(model)

5.4 CVXPY

CVXPY 是一个用于构建和求解凸优化问题的库,但它也可以处理某些非凸问题。CVXPY 提供了一种简单直观的方式来定义优化问题,并使用高效的求解器来找到解。

安装CVXPY
pip install cvxpy
使用示例

问题描述:

最小化目标函数:
f ( x , y ) = ( x − 1 ) 2 + ( y − 2 ) 2 f(x, y) = (x - 1)^2 + (y - 2)^2 f(x,y)=(x1)2+(y2)2

约束条件:
{ x 2 + y 2 ≤ 1 x + y = 1 \begin{cases} x^2 + y^2 \leq 1 \\ x + y = 1 \end{cases} {x2+y21x+y=1

import cvxpy as cp

# 定义变量
x = cp.Variable()
y = cp.Variable()

# 定义目标函数
objective = cp.Minimize((x - 1)**2 + (y - 2)**2)

# 定义约束条件
constraints = [x**2 + y**2 <= 1, x + y == 1]

# 定义问题
problem = cp.Problem(objective, constraints)

# 求解问题
problem.solve()

# 打印结果
print('Optimal value:', problem.value)
print('Optimal solution: x =', x.value, ', y =', y.value)
参数说明
  • cp.Variable(): 定义优化变量。
  • cp.Minimize(): 定义最小化目标函数。
  • cp.Problem(): 定义优化问题,包括目标函数和约束条件。
  • problem.solve(): 求解优化问题。
返回值
  • problem.value: 目标函数在最优解处的值。
  • x.value, y.value: 变量的最优解值。

5.5 各类工具包对比

  • scipy.optimize.minimize 是一个通用的优化函数,适用于各种非线性规划问题。
  • Pyomo 提供了定义和求解复杂优化问题的强大功能,适用于大规模和复杂的非线性规划问题。
  • IPOPT 是一个高效的非线性求解器,特别适合处理大规模非线性约束问题。
  • CVXPY 是一个用于构建和求解凸优化问题的库,但它也可以处理某些非凸问题。
    选择哪个工具包取决于具体问题的复杂程度和求解需求。对于简单的非线性问题

scipy.optimize.minimize 可能足够;对于复杂和大规模的问题,Pyomo 和 IPOPT 提供了更强大的功能和灵活性。CVXPY 是一个用于凸优化问题的 Python 库,尽管其设计初衷是解决凸优化问题,但它也可以用于某些非线性规划问题,特别是那些可以表达为凸问题的非线性优化问题。

6. 非线性规划的建模案例

6.1 工地选址

某公司有 6 6 6个建筑工地要开工,每个工地的位置(用平面坐标系 a , b a,b a,b表示,距离单位:千米)及水泥日用 量 d d d(吨)由下表给出。规划设立两个料场位于 A A A, B B B,日储量各为20吨。假设从料场到工地之间均有 直线道路相连,试确定料场的位置,并制定每天的供应计划,即从 A A A, B B B两料场分别向各工地运送多少吨水泥,使总的吨千米数最小。
在这里插入图片描述
规划问题的核心有三样:决策变量目标函数约束条件

决策变量包括哪些?首先两个料场的坐标未知吧,坐标有横纵坐标于是这就有了四个变量;两个料场到六个工地 12 12 12条线路上的运输量也未知吧,于是这就又来了12个变量,一共是 16 16 16个。距离可以用 Euclid 距离来计算。

解题思路

要解决这个问题,我们需要使用线性规划方法,通过设置目标函数和约束条件来优化料场位置和运输计划。具体步骤如下:

  1. 决策变量

    • 料场A的位置 (x1, y1)
    • 料场B的位置 (x2, y2)
    • 从料场A到工地i的运输量 (tA_i),i = 1,…,6
    • 从料场B到工地i的运输量 (tB_i),i = 1,…,6
  2. 目标函数

    • 我们的目标是最小化总的吨千米数。即从料场A和B分别到各工地的运输量乘以距离之和:
      minimize ∑ i = 1 6 ( t A i ⋅ dist ( A , 工地 i ) + t B i ⋅ dist ( B , 工地 i ) ) \text{minimize} \quad \sum_{i=1}^6 \left( tA_i \cdot \text{dist}(A, 工地i) + tB_i \cdot \text{dist}(B, 工地i) \right) minimizei=16(tAidist(A,工地i)+tBidist(B,工地i))
  3. 约束条件

    • 各工地的水泥需求必须得到满足:
      t A i + t B i = d i , i = 1 , 2 , . . . , 6 tA_i + tB_i = d_i, \quad i = 1,2,...,6 tAi+tBi=di,i=1,2,...,6
    • 每个料场的运输总量不能超过其日储量:
      ∑ i = 1 6 t A i ≤ 20 \sum_{i=1}^6 tA_i \leq 20 i=16tAi20
      ∑ i = 1 6 t B i ≤ 20 \sum_{i=1}^6 tB_i \leq 20 i=16tBi20
    • 所有运输量非负:
      t A i ≥ 0 , t B i ≥ 0 , i = 1 , 2 , . . . , 6 tA_i \geq 0, \quad tB_i \geq 0, \quad i = 1,2,...,6 tAi0,tBi0,i=1,2,...,6
数学建模公式

我们用Python和优化库(如SciPy或PuLP)来解决这个优化问题。

import numpy as np
from scipy.optimize import minimize

# 工地的位置和需求
a = np.array([1.25, 8.75, 0.5, 5.75, 3, 7.25])
b = np.array([1.25, 0.75, 4.75, 5, 6.5, 7.25])
d = np.array([3, 5, 4, 7, 6, 11])

# 目标函数
def objective(x):
    s = 0
    for i in range(6):
        s += x[4+i] * np.sqrt((x[0] - a[i])**2 + (x[1] - b[i])**2)
        s += x[10+i] * np.sqrt((x[2] - a[i])**2 + (x[3] - b[i])**2)
    return s

# 约束条件
constraints = []

# 各工地的水泥需求必须得到满足
for i in range(6):
    constraints.append({'type': 'eq', 'fun': lambda x, i=i: x[4+i] + x[10+i] - d[i]})

# 每个料场的运输总量不能超过其日储量
constraints.append({'type': 'ineq', 'fun': lambda x: 20 - sum(x[4:10])})
constraints.append({'type': 'ineq', 'fun': lambda x: 20 - sum(x[10:16])})

# 初始猜测
x0 = np.array([0, 0, 0, 0] + [1]*12)

# 求解
result = minimize(objective, x0, constraints=constraints)

# 结果展示
print("料场A的位置: ({:.2f}, {:.2f})".format(result.x[0], result.x[1]))
print("料场B的位置: ({:.2f}, {:.2f})".format(result.x[2], result.x[3]))
for i in range(6):
    print("从料场A到工地{}的运输量: {:.2f}吨".format(i+1, result.x[4+i]))
    print("从料场B到工地{}的运输量: {:.2f}吨".format(i+1, result.x[10+i]))
print("总共运输的最少吨数:{:.2f}吨".format(np.sum(result.x[4:15])))
代码解析
  • 目标函数 objective(x):计算总的吨千米数。
  • 约束条件 constraints:包括工地需求的等式约束和料场运输总量的不等式约束。
  • 初始猜测 x0:给定一个初始猜测值。
  • 求解 minimize(objective, x0, constraints=constraints):使用SciPy的minimize函数进行求解。

通过上述步骤,我们可以求得料场的最优位置和每天的运输计划。

料场A的位置: (5.75, 5.00)
料场B的位置: (5.75, 5.00)
从料场A到工地1的运输量: 1.50吨
从料场B到工地1的运输量: 1.50吨
从料场A到工地2的运输量: 2.51吨
从料场B到工地2的运输量: 2.49吨
从料场A到工地3的运输量: 2.00吨
从料场B到工地3的运输量: 2.00吨
从料场A到工地4的运输量: 3.51吨
从料场B到工地4的运输量: 3.49吨
从料场A到工地5的运输量: 3.00吨
从料场B到工地5的运输量: 3.00吨
从料场A到工地6的运输量: 5.49吨
从料场B到工地6的运输量: 5.51吨
总共运输的最少吨数:{}30.49

6.2 职称晋级与评审规划

建立模型

为了设计符合要求的职工调薪方案,我们需要解决一个线性规划问题。具体而言,我们有以下几个目标和约束条件:

  1. 总工资预算不超过150万元
  2. 每级职工人数不超过编制人数
  3. II、III级职工的晋升人数尽量达到现有人数的20%

我们将问题分解为三个子问题,并用线性规划的方法来求解。

1) 总工资预算约束

设:

  • 由II级晋升为I级的人数为 x 1 x_1 x1
  • 由III级晋升为II级的人数为 x 2 x_2 x2
  • 新招聘的III级职工人数为 x 3 x_3 x3

总工资预算的约束为:
50000 ( 9 + x 1 ) + 30000 ( 12 − x 1 + x 2 ) + 20000 ( 15 − x 2 + x 3 ) ≤ 1500000 50000(9 + x_1) + 30000(12 - x_1+x_2) + 20000(15 - x_2 + x_3) \leq 1500000 50000(9+x1)+30000(12x1+x2)+20000(15x2+x3)1500000
用松弛变量 d 1 − d_1^- d1 d 1 + d_1^+ d1+ 表示未满误差和过盈误差,我们有:
50000 ( 9 + x 1 ) + 30000 ( 12 − x 1 + x 2 ) + 20000 ( 15 − x 2 + x 3 ) + d 1 − − d 1 + = 1500000 50000(9 + x_1) + 30000(12 - x_1+x_2) + 20000(15 - x_2 + x_3) + d_1^- - d_1^+ = 1500000 50000(9+x1)+30000(12x1+x2)+20000(15x2+x3)+d1d1+=1500000

2) 编制人数约束

每级人数不超过编制规定人数的约束为:
9 + x 1 + d 2 − − d 2 + = 12 9 + x_1 + d_2^- - d_2^+ = 12 9+x1+d2d2+=12
12 − x 1 + x 2 + d 3 − − d 3 + = 15 12 - x_1 + x_2 + d_3^- - d_3^+ = 15 12x1+x2+d3d3+=15
15 − x 2 + x 3 + d 4 − − d 4 + = 15 15 - x_2 + x_3 + d_4^- - d_4^+ = 15 15x2+x3+d4d4+=15

3) 晋升人数约束

为了使II级、III级职工的晋升人数尽量达到现有人数的20%,我们有:
x 1 + d 5 − − d 5 + = 3 x_1 + d_5^- - d_5^+ = 3 x1+d5d5+=3
x 2 + d 6 − − d 6 + = 3 x_2 + d_6^- - d_6^+ = 3 x2+d6d6+=3

目标函数

目标函数是我们希望最小化的值,它在综合考虑所有约束的偏差后,给出一个最优解。目标函数如下:
minimize  p 1 ⋅ d 1 + + p 2 ⋅ ( d 2 + + d 3 + + d 4 + ) + p 3 ⋅ ( d 5 − − d 5 + + d 6 − − d 6 + ) \text{minimize}~ p_1 \cdot d_1^+ + p_2 \cdot (d_2^+ + d_3^+ + d_4^+) + p_3 \cdot (d_5^- - d_5^+ + d_6^- - d_6^+) minimize p1d1++p2(d2++d3++d4+)+p3(d5d5++d6d6+)

每一项的含义如下:

  • p 1 ⋅ d 1 + p_1 \cdot d_1^+ p1d1+:最小化预算超出的部分。即,尽量避免总工资超出预算。
  • p 2 ⋅ ( d 2 + + d 3 + + d 4 + ) p_2 \cdot (d_2^+ + d_3^+ + d_4^+) p2(d2++d3++d4+):最小化每一级职工人数超过编制人数的部分。即,尽量避免各级职工人数超过编制人数。
  • p 3 ⋅ ( d 5 − − d 5 + + d 6 − − d 6 + ) p_3 \cdot (d_5^- - d_5^+ + d_6^- - d_6^+) p3(d5d5++d6d6+):最小化晋升比例的偏差。即,尽量使得II级、III级职工的晋升人数达到预期的20%。
解题代码
from scipy.optimize import linprog
import numpy as np

# 定义目标函数的系数 (c)
# c 中每个元素对应一个变量的系数,变量依次为:
# x1, x2, x3, d1-, d1+, d2-, d2+, d3-, d3+, d4-, d4+, d5-, d5+, d6-, d6+
# 其中 p1, p2, p3 是目标函数中不同项的权重
p1, p2, p3 = 1, 1, 1  # 可以根据实际情况调整权重
c = np.array([0, 0, 0, 0, p1, 0, p2, 0, p2, 0, p2, p3, p3, -p3, -p3])

# 定义等式约束矩阵 (A_eq) 和等式约束向量 (b_eq)
# A_eq 中每一行对应一个等式约束,每一列对应一个变量
# b_eq 中每个元素对应等式约束的右侧常数值

A_eq = np.array([
    # 预算约束:20000(x1) + 10000(x2) + 20000(x3) + d1- - d1+ = 390000
    [20000, 10000, 20000, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

    # 编制约束:9 + x1 + d2- - d2+ = 12
    [1, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0],

    # 编制约束:12 - x1 + x2 + d3- - d3+ = 15
    [0, -1, 1, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0],

    # 编制约束:15 - x2 + x3 + d4- - d4+ = 15
    [0, 0, -1, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0],

    # 晋升人数约束:x1 + d5- - d5+ = 3
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0],

    # 晋升人数约束:x2 + d6- - d6+ = 3
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1]
])

# 定义等式约束右侧的常数值
b_eq = np.array([390000, 3, 15, 15, 3, 3])

# 定义变量的边界
# x1 的范围是 [0, 12],因为现有II级职工人数最多可以升为I级
# x2 的范围是 [0, 15],因为现有III级职工人数最多可以升为II级
# x3 的范围是 [0, 15],因为现有III级职工最多可以招聘至编制上限
# d1-, d1+, d2-, d2+, d3-, d3+, d4-, d4+, d5-, d5+, d6-, d6+ 的范围是 [0, 10],误差范围设置为 0 到 10
bounds = [
    (0, 12),  # x1
    (0, 15),  # x2
    (0, 15),  # x3
    (0, 10),  # d1-
    (0, 10),  # d1+
    (0, 10),  # d2-
    (0, 10),  # d2+
    (0, 10),  # d3-
    (0, 10),  # d3+
    (0, 10),  # d4-
    (0, 10),  # d4+
    (0, 10),  # d5-
    (0, 10),  # d5+
    (0, 10),  # d6-
    (0, 10)   # d6+
]
# 使用 scipy.optimize.linprog 求解线性规划问题
# 参数说明:
# - c: 目标函数的系数
# - A_eq: 等式约束矩阵
# - b_eq: 等式约束右侧的常数值
# - bounds: 每个变量的取值范围
# - method: 使用的方法,这里选择 'highs',是目前 scipy 中较新的线性规划求解方法
res = linprog(c, A_eq=A_eq, b_eq=b_eq, bounds=bounds, method='highs')

# 打印结果
print(res)
理解松弛变量 d n − d_n^- dn d n + d_n^+ dn+

对于约束条件:
50000 ( 9 + x 1 ) + 30000 ( 12 − x 1 + x 2 ) + 20000 ( 15 − x 2 + x 3 ) ≤ 1500000 50000(9 + x_1) + 30000(12 - x_1+x_2) + 20000(15 - x_2 + x_3) \leq 1500000 50000(9+x1)+30000(12x1+x2)+20000(15x2+x3)1500000

我们引入松弛变量 d 1 − d_1^- d1 d 1 + d_1^+ d1+ 将其转化为等式:
50000 ( 9 + x 1 ) + 30000 ( 12 − x 1 + x 2 ) + 20000 ( 15 − x 2 + x 3 ) + d 1 − − d 1 + = 1500000 50000(9 + x_1) + 30000(12 - x_1+x_2) + 20000(15 - x_2 + x_3) + d_1^- - d_1^+ = 1500000 50000(9+x1)+30000(12x1+x2)+20000(15x2+x3)+d1d1+=1500000

  • d 1 + d_1^+ d1+ 表示“过盈误差”,即超出预算的部分。它是一个正数或零。
  • d 1 − d_1^- d1 表示“未满误差”,即预算不足的部分。它也是一个正数或零。

在此等式中,如果总工资 50000 ( 9 + x 1 ) + 30000 ( 12 − x 1 + x 2 ) + 20000 ( 15 − x 2 + x 3 ) 50000(9 + x_1) + 30000(12 - x_1+x_2) + 20000(15 - x_2 + x_3) 50000(9+x1)+30000(12x1+x2)+20000(15x2+x3) 刚好等于 1500000,那么 d 1 + d_1^+ d1+ d 1 − d_1^- d1 都为零。如果总工资超出1500000元,那么 d 1 + d_1^+ d1+ 为正,表示超出的金额, d 1 − d_1^- d1 为零。如果总工资不足1500000元,那么 d 1 − d_1^- d1 为正,表示不足的金额, d 1 + d_1^+ d1+ 为零。

7. 整数规划与指派问题

7.1 整数规划的基本概念

整数规划(Integer Programming, IP) 是一种特殊的线性规划问题,其中一些或所有决策变量必须取整数值。整数规划可以分为以下几类:

  1. 纯整数规划:所有决策变量必须取整数值。
  2. 混合整数规划(Mixed Integer Programming, MIP):部分决策变量取整数值,其他决策变量可以取连续值。
  3. 二进制整数规划(Binary Integer Programming, BIP):决策变量仅能取0或1的值。

整数规划在实际应用中有广泛的应用,例如在调度问题、资源分配问题、物流问题和资本预算问题中,整数约束往往是必需的。

整数规划的标准形式可以表示为:

minimize c T x subject to A x ≤ b x ∈ Z n 或 x i ∈ { 0 , 1 } , ∀ i \begin{aligned} & \text{minimize} & & c^T x \\ & \text{subject to} & & Ax \leq b \\ & & & x \in \mathbb{Z}^n \quad \text{或} \quad x_i \in \{0, 1\}, \forall i \end{aligned} minimizesubject tocTxAxbxZnxi{0,1},i

其中, c c c b b b 是已知的向量, A A A 是已知的矩阵, x x x 是待求解的整数向量。

7.2 分支定界法

分支定界法(Branch and Bound, B&B) 是求解整数规划问题的一种常用方法。它是一种系统的搜索方法,通过构建解空间树来探索所有可能的解,但通过剪枝技术避免了对每一个可能的解进行穷举。

基本步骤

  1. 初始问题求解:首先忽略整数约束,求解相应的线性规划问题,得到松弛问题的最优解。

  2. 分支:如果松弛问题的最优解不是整数解,选择一个非整数变量,将问题分解为两个子问题,其中一个子问题约束该变量向下取整,另一个子问题约束该变量向上取整。

  3. 界定:对于每个子问题,计算其松弛问题的最优解。如果某个子问题的松弛问题解不可行,或其最优值不优于已知的整数解,则舍弃该子问题。

  4. 剪枝:如果子问题的松弛问题解是整数解,并且优于已知最优整数解,则更新当前最优解。继续搜索其他子问题。

  5. 终止条件:当所有子问题都被处理或舍弃时,算法终止,当前最优整数解即为最优解。

7.3 指派问题与匈牙利法

指派问题(Assignment Problem) 是一种特殊的整数规划问题,旨在将任务分配给工人、机器或其他资源,以最小化总成本或总时间。

指派问题的标准形式可以表示为:

minimize ∑ i = 1 n ∑ j = 1 n c i j x i j subject to ∑ j = 1 n x i j = 1 , i = 1 , … , n ∑ i = 1 n x j = 1 , j = 1 , … , n x i j ∈ { 0 , 1 } \begin{aligned} & \text{minimize} & & \sum_{i=1}^n \sum_{j=1}^n c_{ij} x_{ij} \\ & \text{subject to} & & \sum_{j=1}^n x_{ij} = 1, \quad i=1, \ldots, n \\ & & & \sum_{i=1}^n x_{j} = 1, \quad j=1, \ldots, n \\ & & & x_{ij} \in \{0, 1\} \end{aligned} minimizesubject toi=1nj=1ncijxijj=1nxij=1,i=1,,ni=1nxj=1,j=1,,nxij{0,1}

其中, c i j c_{ij} cij 是将任务 i i i 分配给工人 j j j 的成本, x i j x_{ij} xij 是二进制变量,当任务 i i i 被分配给工人 j j j 时, x i j = 1 x_{ij} = 1 xij=1,否则 x i j = 0 x_{ij} = 0 xij=0

匈牙利法(Hungarian Method) 是一种有效求解指派问题的算法,能够在多项式时间内找到最优解。

匈牙利法的步骤

  1. 构造初始矩阵:从原始成本矩阵中减去每行的最小值,然后减去每列的最小值。

  2. 覆盖零:用尽可能少的水平线和垂直线覆盖所有的零。

  3. 调整矩阵:如果覆盖零的线数等于矩阵的阶数,则找到最优指派;否则,对未覆盖的元素进行调整,重复覆盖零的过程,直到线数等于矩阵的阶数。

  4. 确定最优解:根据调整后的矩阵确定最优指派。

匈牙利法通过一系列矩阵变换和调整,能够有效找到指派问题的最优解,并广泛应用于资源分配、任务调度等领域。

8. 一些拓展

8.1 动态规划与贪心算法

8.2 博弈论与排队论

8.3 多目标规划

8.4 Monte Carlo模拟

9. 一些奇奇怪怪的知识点

9.1 半正定矩阵和正定矩阵分别是什么,两者有什么联系和区别

基本概念

半正定矩阵和正定矩阵是线性代数中的重要概念,常用于二次型、优化理论等领域。它们都与矩阵的特征值和二次型有关。

  • 半正定矩阵 (Positive Semidefinite Matrix)

一个对称矩阵 A ∈ R n × n A \in \mathbb{R}^{n \times n} ARn×n 被称为半正定矩阵,如果对于所有的非零向量 x ∈ R n x \in \mathbb{R}^n xRn,都有:

x T A x ≥ 0 x^T A x \geq 0 xTAx0

这意味着该矩阵的所有特征值都是非负的。

  • 正定矩阵 (Positive Definite Matrix)

一个对称矩阵 A ∈ R n × n A \in \mathbb{R}^{n \times n} ARn×n 被称为正定矩阵,如果对于所有的非零向量 x ∈ R n x \in \mathbb{R}^n xRn,都有:

x T A x > 0 x^T A x > 0 xTAx>0

这意味着该矩阵的所有特征值都是正的。

联系与区别
  1. 特征值

    • 半正定矩阵:所有特征值都是非负的,即 λ i ≥ 0 \lambda_i \geq 0 λi0
    • 正定矩阵:所有特征值都是正的,即 λ i > 0 \lambda_i > 0 λi>0
  2. 二次型

    • 半正定矩阵:对于所有的 x ≠ 0 x \neq 0 x=0 x T A x ≥ 0 x^T A x \geq 0 xTAx0
    • 正定矩阵:对于所有的 x ≠ 0 x \neq 0 x=0 x T A x > 0 x^T A x > 0 xTAx>0
  3. 定义的强度

    • 正定矩阵是半正定矩阵的一个特例。所有正定矩阵都是半正定的,但并非所有半正定矩阵都是正定的。
  4. 判定方法

    • 半正定矩阵:检查矩阵的所有特征值是否为非负;或者使用主子式判定法(所有顺序主子式均非负)。
    • 正定矩阵:检查矩阵的所有特征值是否为正;或者使用主子式判定法(所有顺序主子式均正)。
  • 半正定矩阵示例

A = ( 1 0 0 0 ) A = \begin{pmatrix} 1 & 0 \\ 0 & 0 \end{pmatrix} A=(1000)

特征值为 λ 1 = 1 \lambda_1 = 1 λ1=1 λ 2 = 0 \lambda_2 = 0 λ2=0,因此 A A A 是半正定的。

  • 正定矩阵示例

B = ( 2 1 1 2 ) B = \begin{pmatrix} 2 & 1 \\ 1 & 2 \end{pmatrix} B=(2112)

特征值为 λ 1 = 3 \lambda_1 = 3 λ1=3 λ 2 = 1 \lambda_2 = 1 λ2=1,因此 B B B 是正定的。

总结

半正定矩阵和正定矩阵都涉及矩阵的特征值和二次型。半正定矩阵的特征值非负,正定矩阵的特征值正。正定矩阵是半正定矩阵的一个特例。理解它们之间的联系和区别对深入掌握矩阵理论和应用非常重要。

9.2 线性函数和非线性函数的区别

定义和基本形式
  • 线性函数

    • 一个线性函数具有以下基本形式:
      f ( x ) = a x + b f(x) = ax + b f(x)=ax+b
      其中 a a a b b b 是常数, x x x 是自变量。
    • 线性函数的特征是图像是一条直线,其斜率由系数 a a a 决定,截距由 b b b 决定。
    • 一般形式的线性函数(多元线性函数)可以表示为:
      f ( x 1 , x 2 , … , x n ) = a 1 x 1 + a 2 x 2 + … + a n x n + b f(x_1, x_2, \ldots, x_n) = a_1 x_1 + a_2 x_2 + \ldots + a_n x_n + b f(x1,x2,,xn)=a1x1+a2x2++anxn+b
      其中 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 是系数, b b b 是常数。
  • 非线性函数

    • 一个非线性函数不满足线性函数的特性,其形式可以非常多样。例如:
      f ( x ) = a x 2 + b x + c f(x) = ax^2 + bx + c f(x)=ax2+bx+c
      或者:
      f ( x ) = e x , f ( x ) = log ⁡ ( x ) , f ( x ) = sin ⁡ ( x ) f(x) = e^x, \quad f(x) = \log(x), \quad f(x) = \sin(x) f(x)=ex,f(x)=log(x),f(x)=sin(x)
    • 非线性函数的图像通常不是直线,可以是曲线、指数函数、对数函数、三角函数等。
    • 非线性函数在多元情况下的形式也更加复杂,例如:
      f ( x 1 , x 2 ) = x 1 2 + x 2 2 f(x_1, x_2) = x_1^2 + x_2^2 f(x1,x2)=x12+x22
      或:
      f ( x 1 , x 2 ) = e x 1 x 2 f(x_1, x_2) = e^{x_1 x_2} f(x1,x2)=ex1x2
超位性和齐次性
  • 线性函数

    • 满足叠加性(超位性):
      f ( x 1 + x 2 ) = f ( x 1 ) + f ( x 2 ) f(x_1 + x_2) = f(x_1) + f(x_2) f(x1+x2)=f(x1)+f(x2)
    • 满足齐次性
      f ( k x ) = k f ( x ) f(kx) = kf(x) f(kx)=kf(x)
      其中 k k k 是常数。
    • 因此,线性函数的解可以通过线性组合来求得。
  • 非线性函数

    • 不满足叠加性和齐次性。例如,对于 f ( x ) = x 2 f(x) = x^2 f(x)=x2
      f ( x 1 + x 2 ) ≠ f ( x 1 ) + f ( x 2 ) f(x_1 + x_2) \neq f(x_1) + f(x_2) f(x1+x2)=f(x1)+f(x2)
      f ( k x ) ≠ k f ( x ) f(kx) \neq kf(x) f(kx)=kf(x)
求解方法
  • 线性函数

    • 可以使用线性代数和线性规划等方法求解。
    • 线性问题通常可以通过矩阵运算、线性方程组的解法(如高斯消元法)等方法解决。
  • 非线性函数

    • 求解方法更加复杂,通常需要数值方法,例如牛顿法、梯度下降法等。
    • 非线性规划问题的求解需要专门的优化算法,如拉格朗日乘数法、约束优化中的KKT条件、遗传算法等。
实际应用
  • 线性函数

    • 应用于许多简单和基础的问题,如线性回归、资源分配、网络流量优化等。
    • 线性模型在工程、经济、物理等领域有广泛应用。
  • 非线性函数

    • 用于描述更复杂的现象,如机器学习中的非线性模型、复杂系统的模拟、生物过程、化学反应、经济学中的非线性动态模型等。
    • 非线性模型能够捕捉复杂关系和行为,因此在现代科学和工程中占据重要地位。

线性函数由于其简单性和易解性,适用于许多基础和简单的问题。而非线性函数虽然复杂,但能够描述和解决更多实际中的复杂现象和问题。因此,在实际应用中,选择线性还是非线性函数取决于问题的性质和要求。

9.3 分支定界法的时间复杂度

分支定界法的时间复杂度因素
  1. 问题规模:变量的数量 N N N
  2. 分支数量:每个分支点可能会分解成多个子问题。
  3. 搜索树的深度:树的深度等于变量的数量 N N N,因为每个变量都可能需要分支。
  4. 剪枝效果:剪枝能够有效减少需要探索的节点数。
指数级复杂度的原因

分支定界法通过递归地分解问题,构建一棵搜索树。每个节点对应一个子问题,并且每个子问题的解空间都是原问题的一个子集。

  • 树的构建:假设每次分支将一个问题分成两个子问题,那么在最坏的情况下,树的每一层的节点数会翻倍。因此,对于 N N N 个变量,最坏情况下树的叶子节点数为 2 N 2^N 2N
  • 分支和搜索:在最坏的情况下,需要对每个可能的解进行探索。虽然剪枝可以减少实际探索的节点数,但在没有有效剪枝的情况下,复杂度仍然是指数级的。
剪枝的影响

剪枝技术通过排除一些不必要的分支来减少计算量。有效的剪枝可以显著降低实际需要探索的节点数,从而提高算法效率。然而,剪枝的效果很大程度上取决于具体问题和剪枝策略的有效性。

复杂度示例

考虑一个简单的二进制整数规划问题,其中每个变量 x i x_i xi 可以取 0 或 1:

minimize c 1 x 1 + c 2 x 2 + … + c N x N subject to ∑ i = 1 N a i j x i ≤ b j , ∀ j ∈ { 1 , 2 , … , M } x i ∈ { 0 , 1 } , ∀ i ∈ { 1 , 2 , … , N } \begin{aligned} & \text{minimize} & & c_1 x_1 + c_2 x_2 + \ldots + c_N x_N \\ & \text{subject to} & & \sum_{i=1}^N a_{ij} x_i \leq b_j, \quad \forall j \in \{1, 2, \ldots, M\} \\ & & & x_i \in \{0, 1\}, \quad \forall i \in \{1, 2, \ldots, N\} \end{aligned} minimizesubject toc1x1+c2x2++cNxNi=1Naijxibj,j{1,2,,M}xi{0,1},i{1,2,,N}

对于这个问题,分支定界法在最坏情况下需要探索所有可能的 2 N 2^N 2N 个解,即复杂度为 O ( 2 N ) O(2^N) O(2N)

10. 学习心得

本章学习了线性规划的基本概念、掌握使用Numpy对矩阵进行基本操作(创建、运算、合并、分解)。
处理线性规划问题时,需要对问题进行建模,将线性规划整理为标准形式(程序如matlab底层会将标准形式转换为规范形式进行求解),进行coding得到最优解。
本章的示例中列举两种编程求解方法:scipy的linprog函数 和 pulp工具包

  • scipy.optimize.linprog 是一个简单易用的函数,适用于基本的线性规划问题。
  • PuLP 提供了更强大的功能和灵活性,适用于复杂的线性规划问题。

对于非线性规划问题,可以使用SciPy的minimize函数、CVXPY等工具包进行编程求解。

求解4.2 农民承包土地问题时,分别使用scipy的linprog函数 和 pulp工具包对模型进行求解;
在求解问题6.2 职称晋级与评审规划时,掌握了一个新技巧:对于未知范围的参数,可以引入松弛变量 d n − d_n^- dn d n + d_n^+ dn+建立模型。

本次还学习了一些拓展知识:动态规划与贪心算法、博弈论与排队论、多目标规划和Monte Carlo模拟。

超级喜欢这句话:我们解决问题的思路是将不熟悉的问题,转换成熟悉的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1867120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.NET C# 使用OpenCV实现人脸识别

.NET C# 使用OpenCV实现模型训练、人脸识别 码图~~~ 1 引入依赖 OpenCvSHarp4 - 4.10.0.20240616 OpenCvSHarp4.runtime.win - 4.10.0.20240616 2 人脸数据存储结构 runtime directory | face | {id}_{name} | *.jpg id - 不可重复 name - 人名 *.jpg - 人脸照片3 Demo 3.…

搞定求职难题:工作岗位列表+简历制作工具 | 开源专题 No.75

SimplifyJobs/New-Grad-Positions Stars: 8.5k License: NOASSERTION 这个项目是一个用于分享和跟踪美国、加拿大或远程职位的软件工作机会列表。该项目的核心优势和关键特点如下&#xff1a; 自动更新新岗位信息便捷地提交问题进行贡献提供一键申请选项 BartoszJarocki/cv…

SR655 OCP3 网卡Legacy PXE 轮循设置

1、更改UEFI Boot Mode为UEFI&#xff0c;保存重启服务器&#xff0c;再次进入UEFI界面调整如下图例 更改如下所有网卡legacy 为PXE。后将Boot Mode 更改为legacy,保存退出。 如下图例操作依次更改所有网卡口 2、步骤1&#xff0c;更改Boot Mode 为Legacy保存退出重启服器后&…

SAP揭秘者-在QM标准功能增加取消UD的功能第二季

文章摘要&#xff1a; 上篇文章我已经给大家介绍怎么开发两个程序来取消UD&#xff0c;但是上篇文章中有提到这个时候去直接执行ZQEVAC40程序去取消物料凭证 则会报错&#xff0c;那么为了解决这个报错&#xff0c;我们需要更改后台配置。 接下来我给大家讲后台配置该怎么配置&…

Jetpack架构组件_Navigaiton组件_1.Navigaiton切换Fragment

1.Navigation主要作用 方便管理Fragment &#xff08;1&#xff09;方便我们管理Fragment页面的切换 &#xff08;2&#xff09;可视化的页面导航图&#xff0c;便于理清页面间的关系。 &#xff08;3&#xff09;通过destination和action完成页面间的导航 &#xff08;4&a…

Docker 命令——安全

我们将学习两个命令。第一个命令是 docker container run 命令&#xff0c;这样你就能看到使用该命令的一些好处。其次&#xff0c;我们将看看 docker container diff 命令&#xff0c;你可以用它来查看在已有的镜像基础上做了什么。让我们看看如何使用这两个命令来确保容器的安…

【ARM-Linux篇】项目:智能家居

一、项目概述 •项目功能 通过语音控制客厅灯、卧室灯、风扇、人脸识别开门等,可以进行火灾险情监测,可以并且实现Sockect发送指令远程控制各类家电等 •项目描述 全志H616通过串口连接各模块硬件,检测语音的识别结果,分析语音识别的结果来对家电设备进行控制。摄像头拍…

山东大学多核并行2024年回忆版

2024.6.13回忆版 矩阵向量乘不可整除代码 集合通信与点对点通信的区别 块划分、循环划分、循环块划分&#xff08;14个向量&#xff0c;4个进程&#xff09; 按行访问还是按列访问快 SISD系统问题 循环依赖问题 问题&#xff1a;为什么不能对这个循环并行化&#xff0…

Vue移动端动态表单生成组件

FormCreate 是一个可以通过 JSON 生成具有动态渲染、数据收集、验证和提交功能的表单生成组件。支持6个UI框架&#xff0c;适配移动端&#xff0c;并且支持生成任何 Vue 组件。内置20种常用表单组件和自定义组件&#xff0c;再复杂的表单都可以轻松搞定。 帮助文档 | 源码下载…

科技赋能·创领未来丨智合同和百胜中国就Contract AI Studio项目达成合作

#智合同 #百胜中国 #AIGC #NLP #LLM #Contract AI Studio 近期&#xff0c;国内AIGC和LLM大语言模型发展可谓是如火如荼&#xff0c;其迅速崛起为社会和产业发展起到了非常重要的作用。人们利用AI技术&#xff08;AIGC、LLM大语言模型、NLP等&#xff09;将其赋能到企业生…

【ai】tx2 nx:ubuntu18.04 yolov4-triton-tensorrt 成功部署server 运行

isarsoft / yolov4-triton-tensorrt运行发现插件未注册? 【ai】tx2 nx: jetson Triton Inference Server 部署YOLOv4 【ai】tx2 nx: jetson Triton Inference Server 运行YOLOv4 对main 进行了重新构建 【ai】tx2 nx :ubuntu查找NvInfer.h 路径及哪个包、查找符号【ai】tx2…

Linux系统安装和卸载nginx

&#x1f4d6;Linux系统安装和卸载nginx ✅下载✅安装✅启动nginx✅安装成系统服务✅常见问题&#xff1a;80端口被占用了✅卸载✅目录结构 以下介绍的是以源码编译安装方式&#xff1a; ✅下载 官方地址&#xff1a;https://nginx.org/en/download.html 123云盘地址&#x…

YOLOv8数据集标注

1 简介 数据集是必不可少的部分&#xff0c;数据集的优劣直接影响训练效果。一般来说&#xff0c;一个完整的数据集应该包括训练集、测试集和验证集。通常&#xff0c;数据集会被划分为训练集和测试集&#xff0c;比如将数据集的70%用作训练集&#xff0c;30%用作测试集。在进行…

【知识学习】Unity3D——Surface Shaderlightning的概念及使用方法示例

Unity3D是一个广泛使用的跨平台游戏引擎&#xff0c;它提供了强大的图形渲染功能。在Unity中&#xff0c;Shader是用于控制图形渲染过程的程序&#xff0c;它们运行在GPU上&#xff0c;用于计算屏幕上每个像素的颜色。Surface Shader和Lighting是Unity Shader编程中非常重要的概…

JAVA期末速成库(7)第七、八章

一、习题介绍 第七章 Check Point&#xff1a;P251 7.2&#xff0c;7.4&#xff0c;7.16&#xff0c;8.2 Programming Exercise&#xff1a;7.10&#xff0c;7.14&#xff0c;7.26 二、习题及答案 Check Point&#xff1a; 7.2 When is the memory allocated for an ar…

群体优化算法---石墨烯优化算法介绍以及在期权定价上的应用(Black-Scholes模型来计算欧式期权的理论价格)

介绍 石墨烯算法是一种新兴的优化算法&#xff0c;灵感来自于石墨烯的结构和特性。石墨烯是一种由碳原子构成的二维蜂窝状晶格结构&#xff0c;具有优异的机械、电学和热学性能。石墨烯算法通过模拟石墨烯原子之间的相互作用和迁移&#xff0c;来求解复杂的优化问题 基本概念…

力扣每日一题 特别的排列 DFS 记忆化搜索 位运算 状态压缩DP

Problem: 2741. 特别的排列 &#x1f468;‍&#x1f3eb; 参考题解 &#x1f37b; 暴搜 ⏰ 时间复杂度&#xff1a; O ( N ) O(N) O(N) class Solution {public int specialPerm(int[] nums) {boolean[] visited new boolean[nums.length];return dfs(nums, 0, -1, visit…

一个Mongodb案例-使用地理信息查询酒店

学习mongodb&#xff0c;体会mongodb的每一个使用细节&#xff0c;欢迎阅读威赞的文章。这是威赞发布的第79篇mongodb技术文章&#xff0c;欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题&#xff0c;欢迎在文章下面点个赞&#xff0c;或者关…

vue3项目登录成功后根据角色菜单来跳转指定页面(无首页)

前言&#xff1a;需求不想要首页&#xff0c;登录什么角色跳转到这个角色经常使用的页面。&#xff08;例如&#xff1a;审核者角色的人输入用户名密码成功后就自动跳转到待审核的页面&#xff0c;仓库管理员登录成功则自动跳转到仓库列表&#xff09; 需要解决的点和想法&…

Linux笔记之Bash脚本中的EOF

Linux笔记之Bash脚本中的EOF code review! 文章目录 Linux笔记之Bash脚本中的EOF基本用法自定义结束符变量替换禁用变量替换用于脚本嵌入重定向到文件与命令组合总结 在 Bash 脚本中&#xff0c; EOF 通常用于定义一个多行字符串或文档块。这种技术被称为“Here Document”&a…