【大学生数学建模竞赛】2021年数模竞赛C题通关指南
目录
一、竞赛背景与 C 题引入

全国大学生数学建模竞赛(CUMCM)创办于 1992 年,每年一届,已成为全国高校规模最大的基础性学科竞赛,也是世界上规模最大的数学建模竞赛 。作为首批列入 “高校学科竞赛排行榜” 的 19 项竞赛之一,2021 年有来自全国及美国、马来西亚等国家的 1566 所院校 / 校区、49529 队 (本科 45075 队、专科 4454 队)、14 万多人报名参赛,其影响力可见一斑。比赛时间通常在每年 9 月(一般在上旬某个周末的星期五至下周星期一共 3 天,72 小时) ,本科组从 A、B、C 三道题中选择一题,专科组从 D、E 两道题中选择一题。竞赛题目一般来源于科学与工程技术、人文与社会科学(含经济管理)等领域经过适当简化加工的实际问题,不要求参赛者预先掌握深入的专门知识,主要考查学生运用数学知识、计算机技术和创新思维解决实际问题的综合能力。
2021 年大学生数模竞赛 C 题聚焦于 “企业原材料订购与运输问题”,这是一个在生产运营领域极具实际意义的课题。对于生产企业而言,原材料的订购和运输环节至关重要,直接关系到企业的生产成本、生产效率以及供应链的稳定性。如何在复杂多变的市场环境和供应商条件下,制定出既经济又高效的原材料订购与运输方案,成为了众多企业亟待解决的难题。本题以某建筑和装饰板材生产企业为背景,该企业所用原材料主要分为 A、B、C 三种类型,每年按 48 周安排生产,需要提前制定 24 周的原材料订购和转运计划。在实际运营中,供应商不能保证严格按订货量供货,实际供货量存在波动,同时转运过程中原材料会有一定损耗,这些不确定因素都增加了问题的复杂性和挑战性。 具体来说,该企业每周产能为 2.82 万立方米,每立方米产品需消耗不同体积的 A、B、C 类原材料。为保证正常生产,企业要保持不少于两周生产需求的原材料库存量,且对供应商实际提供的原材料全部收购。每家转运商运输能力为 6000 立方米 / 周,通常一家供应商每周供应的原材料尽量由一家转运商运输,A 类和 B 类原材料采购单价分别比 C 类高 20% 和 10%,三类原材料运输和储存单位费用相同。题目还提供了近 5 年 402 家原材料供应商的订货量和供货量数据,以及 8 家转运商的运输损耗率数据,要求参赛团队结合实际情况,对相关数据进行深入分析,解决一系列与原材料订购和运输相关的问题。 这个题目不仅考查了参赛者对数据处理、分析和建模的能力,还要求参赛者具备一定的实际问题解决能力和创新思维,能够在复杂的约束条件下,找到最优的解决方案。接下来,就让我们一起深入剖析这道题目,探索其中的解题思路和方法。
二、C 题题目深度剖析
(一)题目关键信息提取
- 企业生产相关:企业生产建筑和装饰板材,所用原材料分为 A、B、C 三类,每年按 48 周生产,需提前制定 24 周原材料订购与转运计划。每周产能固定为 2.82 万立方米,每立方米产品对 A、B、C 三类原材料的消耗量不同,分别为 0.6 立方米、0.66 立方米和 0.72 立方米 。企业要维持不少于两周生产需求的原材料库存量,这是保障生产连续性的关键条件。
- 供应商相关:题目提供了近 5 年 402 家供应商的订货量和供货量数据。供应商无法严格按订货量供货,实际供货量存在波动,这一不确定性给企业的原材料供应管理带来挑战。企业对供应商实际提供的原材料全部收购,这意味着企业需要在采购环节充分考虑供应商供货的不稳定因素。
- 转运商相关:有 8 家转运商,每家转运商运输能力为 6000 立方米 / 周,运输过程中原材料存在损耗,题目给出了各转运商的运输损耗率数据。通常一家供应商每周供应的原材料尽量由一家转运商运输,这涉及到转运商的合理分配和运输路线的优化。
- 成本相关:A 类和 B 类原材料采购单价分别比 C 类高 20% 和 10%,而三类原材料运输和储存单位费用相同。这表明在制定订购方案时,采购成本是一个重要的考量因素,尤其是不同类型原材料的价格差异,会影响企业的成本结构。
(二)问题拆解与分析
- 问题一:要求对 402 家供应商的供货特征进行量化分析,建立反映保障企业生产重要性的数学模型,进而确定 50 家最重要的供应商。这需要从供应商的供货稳定性、供货量大小、供货及时性等多个维度进行分析。可以考虑使用一些数据分析方法,如主成分分析、聚类分析等,对供应商的供货数据进行处理,提取关键特征。在建立数学模型时,可以采用层次分析法、熵权法等方法,确定各特征指标的权重,从而综合评价供应商的重要性。
- 问题二:需确定企业至少选择多少家供应商才能满足生产需求,并为这些供应商制定未来 24 周每周最经济的订购方案和损耗最少的转运方案,同时分析方案实施效果。首先要根据企业的产能需求和供应商的供货能力,建立整数规划模型来确定最少供应商数量。在制定订购方案时,以采购成本最小为目标函数,考虑供应商的供货限制、企业的库存要求等约束条件。对于转运方案,以损耗最少为目标,结合转运商的运输能力和损耗率进行优化。最后通过对比不同方案的成本、损耗等指标,分析方案的实施效果。
- 问题三:企业计划多采购 A 类、少采购 C 类原材料以降低转运及仓储成本,同时希望转运商损耗率尽量少,需制定新的订购和转运方案并分析效果。在这个问题中,采购成本和转运损耗是两个主要的优化目标。可以建立多目标规划模型,通过设置不同目标的权重来平衡采购成本和转运损耗。在确定订购方案时,要考虑 A 类和 C 类原材料的采购比例限制,以及供应商的供货能力。转运方案则在满足运输能力的前提下,优先选择损耗率低的转运商。
- 问题四:要根据现有供应商和转运商的实际情况,确定企业每周产能可提高的幅度,并给出未来 24 周的订购和转运方案。这需要综合考虑供应商的供货潜力、转运商的运输能力提升空间以及企业自身的生产能力限制。可以通过建立生产函数模型,将供应商供货量、转运商运输能力等作为自变量,企业产能作为因变量,分析各因素对产能的影响,从而确定产能的提升幅度。在制定订购和转运方案时,要确保新的方案能够适应产能的变化,同时保证成本和损耗在可接受范围内。
三、问题一:供应商重要性分析与筛选
(一)解题思路阐述
在解决这个问题时,我们需要综合考虑多个因素来量化供应商的供货特征,并建立一个能够准确反映其对保障企业生产重要性的数学模型。为了全面评估供应商,我们选取了订货增长量、供货增长量、产品材料、订货总量、供货总量、订货持续性、供货持续性、供货稳定性这 8 个关键指标,构建了一个较为完善的供应商重要性综合评价体系。 订货增长量和供货增长量能反映供应商的供应能力变化趋势,订货总量和供货总量体现了供应商的供应规模,订货持续性和供货持续性展示了供应商供应的稳定性,供货稳定性则直接关系到企业生产的连续性。产品材料类型与企业的生产需求紧密相关,不同类型原材料的采购成本和供应稳定性对企业生产有着重要影响。
在确定各指标权重时,我们采用了组合赋权的方法,将熵权法和层次分析法(AHP)相结合 。熵权法是一种基于数据本身的客观赋权方法,它通过计算指标数据的熵值来确定指标的权重,熵值越小,说明该指标所包含的信息量越大,其权重也就越高。例如,如果某个供应商的供货稳定性指标数据波动很小,熵值低,就表明该指标在评价供应商重要性时作用大。而层次分析法是一种主观赋权方法,它通过专家对各指标相对重要性的判断,构建判断矩阵,进而计算出各指标的权重。这种方法能充分考虑决策者的经验和主观判断。将两者结合,可以取长补短,既利用了数据的客观信息,又融入了专家的主观判断,使权重的确定更加科学合理。
最后,我们使用 TOPSIS 法(Technique for Order Preference by Similarity to an Ideal Solution,逼近理想解排序法),以组合权重作为距离权重对各供应商供货特征进行综合评价与排序 。TOPSIS 法的基本思想是通过计算各评价对象与理想解(正理想解和负理想解)之间的距离,来确定各评价对象的相对优劣程度。正理想解是各指标都取最优值的解,负理想解是各指标都取最差值的解。与正理想解距离越近,同时与负理想解距离越远的供应商,其重要性就越高。通过这种方法,我们可以对 402 家供应商进行全面、客观的评价,从而筛选出 50 家最重要的供应商。
(二)代码实现步骤
- 数据读取
-
- Python 代码示例:
import pandas as pd
# 读取供应商数据,假设数据文件为'supplier_data.csv',包含订货量和供货量等数据
data = pd.read_csv('supplier_data.csv')
# 查看数据前5行,了解数据结构
data.head()
在这段代码中,pd.read_csv是pandas库中用于读取 CSV 文件的函数 。'supplier_data.csv'是数据文件的路径和文件名,通过这个函数,我们将 CSV 文件中的数据读取到一个DataFrame数据结构中,方便后续的数据处理和分析。data.head()函数用于查看数据的前 5 行,它可以帮助我们快速了解数据的结构和内容,检查数据是否正确读取。
- Matlab 代码示例:
data = readtable('supplier_data.csv');
head(data)
Matlab 中使用readtable函数读取 CSV 文件,将数据存储在表格(table)数据类型中 。head(data)同样用于显示表格的前几行数据,以便快速预览数据内容。
- 指标计算
-
- 订货增长量计算代码(Python):
data['order_increase'] = data.groupby('supplier_id')['order_quantity'].diff()
这里使用groupby函数按supplier_id对数据进行分组,然后使用diff函数计算每个供应商的订货量差值,得到订货增长量 。订货增长量反映了供应商在不同时间段内订货量的变化情况,有助于分析供应商的业务增长趋势。
- 供货稳定性计算代码(Python):
import numpy as np
data['supply_stability'] = data.groupby('supplier_id')['supply_quantity'].apply(lambda x: np.std(x) / np.mean(x))
通过groupby函数按供应商分组后,利用apply函数结合numpy库的std(标准差)和mean(均值)函数计算每个供应商供货量的变异系数,以此衡量供货稳定性 。变异系数越小,说明供货量越稳定,供应商的可靠性越高。其他指标如供货增长量、订货总量、供货总量等的计算逻辑类似,都是基于基本的数学运算和数据分组操作。订货总量可以通过对每个供应商的订货量进行求和得到,供货总量同理。订货持续性和供货持续性可以通过判断每周是否有订货或供货记录来计算持续的周数。
- 权重确定
-
- 熵权法确定权重代码(Python):
import numpy as np
def entropy_weight(data):
# 数据标准化
data = (data - data.min()) / (data.max() - data.min())
# 计算比重
p = data / data.sum()
# 计算熵值
e = -np.sum(p * np.log(p), axis = 0) / np.log(len(data))
# 计算权重
w = (1 - e) / np.sum(1 - e)
return w
# 假设指标数据存储在一个DataFrame中,列名为指标名称
indicator_data = data[['order_increase','supply_increase', 'product_material', 'order_total','supply_total',
'order_persistence','supply_persistence','supply_stability']]
entropy_weights = entropy_weight(indicator_data)
熵权法的核心步骤是先对数据进行标准化处理,消除量纲的影响 。然后计算每个指标在各个样本中的比重,再根据比重计算熵值,熵值反映了指标的离散程度。最后通过熵值计算权重,熵值越小,权重越大。
- 层次分析法确定权重代码(Python,使用pyaHP库):
from pyaHP import *
# 构建判断矩阵,根据专家经验判断各指标相对重要性
judgment_matrix = np.array([[1, 2, 3, 4, 5, 6, 7, 8],
[1 / 2, 1, 2, 3, 4, 5, 6, 7],
[1 / 3, 1 / 2, 1, 2, 3, 4, 5, 6],
[1 / 4, 1 / 3, 1 / 2, 1, 2, 3, 4, 5],
[1 / 5, 1 / 4, 1 / 3, 1 / 2, 1, 2, 3, 4],
[1 / 6, 1 / 5, 1 / 4, 1 / 3, 1 / 2, 1, 2, 3],
[1 / 7, 1 / 6, 1 / 5, 1 / 4, 1 / 3, 1 / 2, 1, 2],
[1 / 8, 1 / 7, 1 / 6, 1 / 5, 1 / 4, 1 / 3, 1 / 2, 1]])
root = Node("root")
criteria = []
for i in range(8):
criteria.append(Node(f'c{i + 1}'))
root.addChild(criteria[i])
for i in range(8):
for j in range(8):
criteria[i].setChildWeight(criteria[j], judgment_matrix[i][j])
ahp = AHP(root)
ahp_weights = ahp.getWeights()
层次分析法首先需要构建判断矩阵,判断矩阵中的元素表示两个指标之间的相对重要性程度 。通过专家对各指标重要性的两两比较,确定判断矩阵的值。然后利用pyaHP库构建层次结构模型,计算出各指标的权重。这些权重反映了专家对不同指标在评价供应商重要性时的主观判断。
- 综合评价与排序
-
- TOPSIS 法综合评价和排序代码(Python):
def topsis(data, weights):
# 数据标准化
data = (data - data.min()) / (data.max() - data.min())
# 计算加权标准化矩阵
weighted_data = data * weights
# 确定正理想解和负理想解
positive_ideal = weighted_data.max()
negative_ideal = weighted_data.min()
# 计算与正理想解和负理想解的距离
d_positive = np.sqrt(np.sum((weighted_data - positive_ideal) ** 2, axis = 1))
d_negative = np.sqrt(np.sum((weighted_data - negative_ideal) ** 2, axis = 1))
# 计算综合评价指标
c = d_negative / (d_positive + d_negative)
return c
# 进行TOPSIS综合评价
topsis_scores = topsis(indicator_data, entropy_weights * ahp_weights)
# 将综合评价得分添加到原始数据中
data['topsis_score'] = topsis_scores
# 按综合评价得分降序排序
sorted_data = data.sort_values(by='topsis_score', ascending = False)
# 选取前50家供应商
top_50_suppliers = sorted_data.head(50)
TOPSIS 法首先对指标数据进行标准化处理,然后根据熵权法和层次分析法得到的组合权重,计算加权标准化矩阵 。接着确定正理想解和负理想解,分别代表各指标的最优值和最差值。通过计算每个供应商与正理想解和负理想解的距离,得到综合评价指标。最后,将综合评价得分添加到原始数据中,并按得分降序排序,选取前 50 家供应商作为最重要的供应商。
四、问题二:订购与转运方案制定
(一)数学模型构建
为了解决企业未来 24 周的原材料订购和转运方案问题,我们采用线性规划的方法来构建数学模型。线性规划是一种在满足一系列线性约束条件下,求解线性目标函数最优值的数学方法,非常适合解决这类资源分配和优化问题。
- 目标函数:我们的目标是使企业的采购成本最小化。设\(x_{ij}\)表示第\(i\)周从第\(j\)个供应商订购的原材料数量,\(c_{j}\)表示第\(j\)个供应商提供原材料的单价。则目标函数可以表示为:\(\min \sum_{i = 1}^{24}\sum_{j = 1}^{n}c_{j}x_{ij}\)
这里的双重求和表示对未来 24 周内从每个供应商订购的原材料成本进行累加,通过最小化这个目标函数,我们可以得到最经济的订购方案。
- 约束条件:
-
- 生产需求约束:企业每周的产能是固定的,为 2.82 万立方米,每立方米产品对 A、B、C 三类原材料的消耗量不同。根据这些条件,我们可以建立约束条件,确保每周订购的原材料数量能够满足生产需求。以 A 类原材料为例,假设每立方米产品消耗\(a\)立方米 A 类原材料,那么第\(i\)周订购的 A 类原材料数量\(x_{i1}\)(假设第 1 个供应商提供 A 类原材料)需要满足:\(\sum_{j = 1}^{n_{A}}x_{ij} \geq 2.82 \times a\)
其中\(n_{A}\)表示提供 A 类原材料的供应商数量。对于 B 类和 C 类原材料,也有类似的约束条件,只是消耗系数和供应商数量不同。
-
- 库存约束:企业需要保持不少于两周生产需求的原材料库存量。设\(I_{i - 1}\)表示第\(i - 1\)周结束时的原材料库存量,那么第\(i\)周的库存\(I_{i}\)可以表示为:\(I_{i}=I_{i - 1}+\sum_{j = 1}^{n}x_{ij}-2.82\times(a + b + c)\)
其中\(a\)、\(b\)、\(c\)分别为每立方米产品对 A、B、C 三类原材料的消耗量。同时,要满足库存下限约束\(I_{i}\geq 2\times2.82\times(a + b + c)\),确保库存始终能够满足至少两周的生产需求。
-
- 供应商供货能力约束:每个供应商的供货能力是有限的。设\(s_{j}\)表示第\(j\)个供应商的最大供货量,那么有:\(\sum_{i = 1}^{24}x_{ij} \leq s_{j}\)
这个约束条件保证了我们从每个供应商的订购量不会超过其供货能力。
-
- 转运商运输能力约束:每家转运商的运输能力为 6000 立方米 / 周。设\(y_{ijk}\)表示第\(i\)周从第\(j\)个供应商运输到企业的原材料由第\(k\)个转运商负责运输的数量,\(t_{k}\)表示第\(k\)个转运商的运输能力。则有:\(\sum_{i = 1}^{24}\sum_{j = 1}^{n}y_{ijk} \leq t_{k}\)
同时,为了满足运输关系,还需要有\(x_{ij}=\sum_{k = 1}^{m}y_{ijk}\),其中\(m\)表示转运商的数量,确保从供应商订购的原材料都能通过转运商运输到企业。
-
- 损耗约束:在转运过程中,原材料会有一定的损耗。设\(l_{k}\)表示第\(k\)个转运商的运输损耗率,那么实际到达企业的原材料数量为\((1 - l_{k})y_{ijk}\)。为了保证生产需求,需要满足:\(\sum_{k = 1}^{m}(1 - l_{k})y_{ijk}\geq x_{ij}\)
这个约束条件考虑了运输损耗对原材料供应的影响,确保企业最终收到的原材料数量能够满足订购量的要求。通过以上目标函数和约束条件的构建,我们建立了一个完整的线性规划模型,用于求解企业未来 24 周最经济的订购方案和损耗最少的转运方案。
(二)代码实现详解
- 参数定义:在 Python 中,我们首先需要定义一系列参数来构建和求解线性规划模型。假设我们已经从数据文件中读取了供应商的供货能力、单价、转运商的运输能力和损耗率等数据。
import numpy as np
# 读取供应商数据,假设数据文件为'supplier_data.csv'
supplier_data = np.genfromtxt('supplier_data.csv', delimiter = ',')
# 供应商数量
n = len(supplier_data)
# 转运商数量
m = 8
# 成本矩阵,c[j]表示第j个供应商的单价
c = supplier_data[:, 2]
# 供应商供货能力矩阵,s[j]表示第j个供应商的最大供货量
s = supplier_data[:, 3]
# 转运商运输能力向量,t[k]表示第k个转运商的运输能力
t = np.array([6000] * m)
# 转运商损耗率向量,l[k]表示第k个转运商的运输损耗率,假设从另一个文件读取
loss_data = np.genfromtxt('loss_rate_data.csv', delimiter = ',')
l = loss_data[:, 1]
# 企业每周生产对原材料的需求量,假设每立方米产品对A、B、C三类原材料的消耗量分别为a, b, c
a = 0.6
b = 0.66
c = 0.72
demand = 2.82 * (a + b + c)
在这段代码中,np.genfromtxt函数用于从 CSV 文件中读取数据 。c是成本矩阵,它存储了每个供应商提供原材料的单价,这些单价信息从supplier_data.csv文件的第三列读取(索引为 2)。s是供应商供货能力矩阵,记录了每个供应商的最大供货量,从文件第四列读取(索引为 3)。t是转运商运输能力向量,这里假设每个转运商的运输能力都是 6000 立方米 / 周。l是转运商损耗率向量,从loss_rate_data.csv文件中读取每个转运商的运输损耗率 。demand表示企业每周生产对原材料的需求量,根据每立方米产品对三类原材料的消耗量和每周产能计算得出。
2. 模型求解:接下来,我们使用scipy.optimize库中的linprog函数来求解线性规划模型。linprog函数是scipy库中用于求解线性规划问题的工具,它可以在给定的约束条件下,找到目标函数的最优解。
from scipy.optimize import linprog
# 目标函数系数,将目标函数展开为一维向量形式
f = np.tile(c, 24)
# 初始化约束条件矩阵A和向量b
A = []
b = []
# 生产需求约束
for i in range(24):
row = np.zeros(n * 24)
row[i * n:(i + 1) * n]=1
A.append(row)
b.append(demand)
# 库存约束,这里简化处理,假设初始库存为满足两周需求,后续可根据实际情况调整
initial_inventory = 2 * demand
for i in range(1, 24):
inventory_row = np.zeros(n * 24)
inventory_row[(i - 1) * n:i * n]=1
inventory_row[i * n:(i + 1) * n]= - 1
A.append(inventory_row)
b.append(0)
A.append(np.zeros(n * 24))
A[-1][:n]=1
b.append(initial_inventory - demand)
# 供应商供货能力约束
for j in range(n):
supply_row = np.zeros(n * 24)
supply_row[j::n]=1
A.append(supply_row)
b.append(s[j])
# 转运商运输能力约束,这里简化为只考虑运输总量不超过运输能力,未考虑具体的运输分配关系,后续可完善
for k in range(m):
transport_row = np.zeros(n * 24)
A.append(transport_row)
b.append(t[k])
# 损耗约束,这里简化处理,假设每个转运商负责所有供应商的运输,未考虑实际分配,后续可改进
for i in range(24):
for j in range(n):
loss_row = np.zeros(n * 24)
loss_row[i * n + j]= - 1
for k in range(m):
loss_row[i * n + j]+=(1 - l[k])
A.append(loss_row)
b.append(0)
A = np.array(A)
b = np.array(b)
# 求解线性规划问题
res = linprog(f, A_ub = A, b_ub = b)
if res.success:
optimal_solution = res.x.reshape(24, n)
print('最优订购方案:')
print(optimal_solution)
total_cost = res.fun
print('最小采购成本:', total_cost)
else:
print('未找到可行解')
在这段代码中,首先将目标函数系数f扩展为 24 周的形式,通过np.tile函数将成本矩阵c重复 24 次 。然后逐步构建约束条件矩阵A和向量b。对于生产需求约束,每周都需要满足生产对原材料的需求,因此在A矩阵中,对应每周的供应商订购量位置设置为 1,向量b中对应位置设置为每周的需求量demand。库存约束的构建考虑了每周库存的变化,通过设置前一周和当前周订购量的系数来体现库存的增减关系 。供应商供货能力约束则是在A矩阵中,对于每个供应商在 24 周内的订购量位置设置为 1,向量b中对应位置设置为该供应商的最大供货量s[j]。转运商运输能力约束和损耗约束的构建也遵循类似的逻辑,但这里的实现是简化版本,实际应用中还需要进一步完善,以准确反映运输分配和损耗情况。最后,使用linprog函数求解线性规划问题,A_ub和b_ub分别表示不等式约束矩阵和向量。如果求解成功,res.success为True,我们可以从res.x中获取最优解,并将其重塑为 24 周和供应商数量的二维数组形式,同时从res.fun中获取最小采购成本。如果未找到可行解,则会输出提示信息。通过以上代码实现,我们可以得到满足企业生产需求、成本最小的原材料订购方案,以及考虑损耗情况下的转运方案(虽然当前转运方案部分是简化实现,后续可进一步优化完善)。
五、问题三:新订购与转运方案优化
(一)优化目标与思路
在问题三中,企业旨在通过调整原材料采购策略来降低转运及仓储成本,同时减少转运商的损耗率。由于 A 类原材料采购单价虽高,但每立方米产品对其消耗体积最少(0.6 立方米),C 类原材料采购单价相对较低,但消耗体积最多(0.72 立方米)。在相同产能要求下,增加 A 类原材料采购量,减少 C 类原材料采购量,可降低库存原料总体积,从而降低仓储成本 。例如,假设企业每周产能为 2.82 万立方米,若全部采购 C 类原材料,每周需采购 2.82×0.72 = 2.0304 万立方米;若全部采购 A 类原材料,每周仅需采购 2.82×0.6 = 1.692 万立方米,采购量的减少有助于降低仓储成本。
为实现这一目标,我们需要构建一个多目标优化模型。首先,量化成本目标函数,成本不仅包括采购成本,还涉及仓储成本。设\(x_{ij}\)表示第\(i\)周从第\(j\)个供应商订购的原材料数量,\(c_{j}\)表示第\(j\)个供应商提供原材料的单价,\(s_{ij}\)表示第\(i\)周库存的原材料数量,\(h\)表示单位原材料的仓储成本 。则成本目标函数\(Z_{1}\)可表示为:\(Z_{1}=\sum_{i = 1}^{24}\sum_{j = 1}^{n}c_{j}x_{ij}+\sum_{i = 1}^{24}\sum_{j = 1}^{n}h s_{ij}\)
对于转运损耗率目标函数,设\(y_{ijk}\)表示第\(i\)周从第\(j\)个供应商运输到企业的原材料由第\(k\)个转运商负责运输的数量,\(l_{k}\)表示第\(k\)个转运商的运输损耗率 。则转运损耗率目标函数\(Z_{2}\)可表示为:\(Z_{2}=\sum_{i = 1}^{24}\sum_{j = 1}^{n}\sum_{k = 1}^{m}l_{k}y_{ijk}\)
在构建模型时,还需考虑诸多约束条件。生产需求约束要保证每周订购的原材料能满足生产需求,库存约束需维持不少于两周生产需求的原材料库存量,供应商供货能力约束要确保不超过供应商的最大供货量,转运商运输能力约束要使转运量在转运商的运输能力范围内,损耗约束要保证考虑损耗后实际到达企业的原材料能满足订购量要求 。同时,为体现对 A 类和 C 类原材料采购量的调整,可增加约束条件,如\(\sum_{i = 1}^{24}\sum_{j \in A}x_{ij}\geq\alpha\sum_{i = 1}^{24}\sum_{j = 1}^{n}x_{ij}\)和\(\sum_{i = 1}^{24}\sum_{j \in C}x_{ij}\leq\beta\sum_{i = 1}^{24}\sum_{j = 1}^{n}x_{ij}\),其中\(A\)表示提供 A 类原材料的供应商集合,\(C\)表示提供 C 类原材料的供应商集合,\(\alpha\)和\(\beta\)为预先设定的比例系数,可根据企业对成本和库存的具体要求进行调整 。通过这样的多目标优化模型,可在满足各种实际约束的情况下,找到兼顾成本降低和损耗减少的最优订购与转运方案。
(二)代码调整与实现
在问题二代码的基础上,我们需要对目标函数和约束条件进行相应调整,以实现问题三的多目标优化。这里我们依然使用 Python 结合scipy.optimize库中的linprog函数来进行代码实现 。首先,重新定义目标函数系数。由于是多目标优化,我们采用线性加权法将两个目标函数合并为一个综合目标函数 。假设成本目标函数的权重为\(w_{1}\),转运损耗率目标函数的权重为\(w_{2}\),且\(w_{1}+w_{2}=1\) 。
import numpy as np
from scipy.optimize import linprog
# 假设已读取供应商数据和转运商数据,同问题二代码中的数据读取部分
# 重新定义目标函数系数,考虑成本和损耗率,假设w1和w2分别为成本和损耗率目标函数的权重
w1 = 0.6
w2 = 0.4
# 成本系数,同问题二代码中的c
c = np.array([...])
# 仓储成本系数,假设单位仓储成本为h
h = 0.1
# 损耗率系数,同问题二代码中的l
l = np.array([...])
# 扩展成本系数到24周,同问题二代码中对c的扩展
cost_coeff = np.tile(c, 24)
# 扩展仓储成本系数到24周,假设库存与订购量相关,这里简化为与订购量系数相同
storage_coeff = np.tile(h * c, 24)
# 扩展损耗率系数到24周的运输变量维度,假设运输变量y的索引顺序与x相关
loss_coeff = np.tile(l, len(c) * 24)
# 综合目标函数系数
f = w1 * (cost_coeff + storage_coeff)+w2 * loss_coeff
在这段代码中,首先设定了成本目标函数和转运损耗率目标函数的权重\(w_{1}\)和\(w_{2}\) 。然后,根据问题二已读取的供应商数据得到成本系数c,假设单位仓储成本为h,将其扩展到 24 周的订购量维度得到storage_coeff 。同样,根据转运商数据得到损耗率系数l,并扩展到运输变量的维度得到loss_coeff 。最后,通过线性加权法将成本相关系数和损耗率相关系数合并为综合目标函数系数f 。
接下来,调整约束条件。除了保留问题二中的生产需求约束、库存约束、供应商供货能力约束、转运商运输能力约束和损耗约束外,还需添加 A 类和 C 类原材料采购量的约束条件 。
# 初始化约束条件矩阵A和向量b,同问题二代码
A = []
b = []
# 生产需求约束,同问题二代码
for i in range(24):
row = np.zeros(len(c) * 24)
row[i * len(c):(i + 1) * len(c)] = 1
A.append(row)
b.append(demand)
# 库存约束,同问题二代码,假设初始库存为满足两周需求,后续可根据实际情况调整
initial_inventory = 2 * demand
for i in range(1, 24):
inventory_row = np.zeros(len(c) * 24)
inventory_row[(i - 1) * len(c):i * len(c)] = 1
inventory_row[i * len(c):(i + 1) * len(c)] = -1
A.append(inventory_row)
b.append(0)
A.append(np.zeros(len(c) * 24))
A[-1][:len(c)] = 1
b.append(initial_inventory - demand)
# 供应商供货能力约束,同问题二代码
for j in range(len(c)):
supply_row = np.zeros(len(c) * 24)
supply_row[j::len(c)] = 1
A.append(supply_row)
b.append(s[j])
# 转运商运输能力约束,同问题二代码,这里简化为只考虑运输总量不超过运输能力,未考虑具体的运输分配关系,后续可完善
for k in range(m):
transport_row = np.zeros(len(c) * 24)
A.append(transport_row)
b.append(t[k])
# 损耗约束,同问题二代码,这里简化处理,假设每个转运商负责所有供应商的运输,未考虑实际分配,后续可改进
for i in range(24):
for j in range(len(c)):
loss_row = np.zeros(len(c) * 24)
loss_row[i * len(c)+j]= -1
for k in range(m):
loss_row[i * len(c)+j]+=(1 - l[k])
A.append(loss_row)
b.append(0)
# 添加A类和C类原材料采购量约束
# 假设A类供应商索引范围是0到a_num - 1,C类供应商索引范围是c_start到len(c) - 1
a_num = 10
c_start = 20
alpha = 0.4
beta = 0.3
a_constraint_row = np.zeros(len(c) * 24)
c_constraint_row = np.zeros(len(c) * 24)
for i in range(24):
a_constraint_row[i * len(c):(i + 1) * len(c)][:a_num]=1
c_constraint_row[i * len(c):(i + 1) * len(c)][c_start:]=1
A.append(a_constraint_row)
b.append(alpha * np.sum(cost_coeff))
A.append(c_constraint_row)
b.append(beta * np.sum(cost_coeff))
A = np.array(A)
b = np.array(b)
在这段代码中,先按照问题二的方式构建了生产需求、库存、供应商供货能力、转运商运输能力和损耗等约束条件 。然后,添加 A 类和 C 类原材料采购量约束条件 。假设 A 类供应商索引范围是 0 到a_num - 1,C 类供应商索引范围是c_start到len(c) - 1,根据设定的比例系数alpha和beta,构建相应的约束行向量,并添加到约束条件矩阵A和向量b中 。最后,使用linprog函数求解多目标优化问题。
# 求解线性规划问题
res = linprog(f, A_ub = A, b_ub = b)
if res.success:
optimal_solution = res.x.reshape(24, len(c))
print('最优订购方案:')
print(optimal_solution)
total_cost = w1 * res.fun / (w1 + w2)
total_loss = w2 * res.fun / (w1 + w2)
print('总成本:', total_cost)
print('总损耗:', total_loss)
else:
print('未找到可行解')
在这段代码中,使用linprog函数求解多目标优化问题,A_ub和b_ub分别表示不等式约束矩阵和向量 。如果求解成功,将最优解重塑为 24 周和供应商数量的二维数组形式,并根据权重计算出总成本和总损耗 。如果未找到可行解,则输出提示信息 。通过以上代码调整,实现了问题三的多目标优化,得到了满足企业降低成本和减少损耗要求的新订购与转运方案 。
六、问题四:产能提升与方案规划
(一)分析方法与模型
在确定企业每周产能可提高的幅度并制定相应订购和转运方案时,我们需要全面考虑供应商的供货能力和转运商的运输能力 。首先,构建生产函数模型来分析产能与各因素之间的关系。设企业每周产能为\(P\),供应商的供货量为\(S_{j}\)(\(j = 1,2,\cdots,n\),\(n\)为供应商数量),转运商的运输量为\(T_{k}\)(\(k = 1,2,\cdots,m\),\(m\)为转运商数量),运输损耗率为\(l_{k}\),则生产函数模型可表示为:\(P=\min\left(\sum_{j = 1}^{n}S_{j},\sum_{k = 1}^{m}(1 - l_{k})T_{k}\right)\)
这个模型的含义是,企业的产能受到供应商供货量和考虑损耗后转运商实际运输到企业的原材料量的限制,取两者中的最小值作为企业的实际产能 。例如,如果供应商的供货总量为 10 万立方米,但由于转运商的运输能力和损耗问题,实际运输到企业的原材料量只有 8 万立方米,那么企业的产能就只能达到 8 万立方米 。
为了确定产能可提高的幅度,我们需要对供应商的供货潜力和转运商的运输能力提升空间进行分析 。对于供应商,我们可以通过分析其历史供货数据,评估其在不影响供货稳定性的前提下,最大可能的供货增量 。比如,某些供应商在过去的供货中,有部分周次的供货量远低于其最大供货能力,通过与供应商沟通协商,有可能挖掘出这些潜在的供货增量 。对于转运商,考虑是否可以通过优化运输路线、增加运输设备等方式提高其运输能力 。假设通过调查分析,确定第\(j\)个供应商的供货增量为\(\Delta S_{j}\),第\(k\)个转运商的运输能力提升量为\(\Delta T_{k}\),则新的产能模型为:\(P'=\min\left(\sum_{j = 1}^{n}(S_{j}+\Delta S_{j}),\sum_{k = 1}^{m}((1 - l_{k})(T_{k}+\Delta T_{k}))\right)\)
通过比较\(P\)和\(P'\),我们就能确定企业每周产能可提高的幅度 。在制定未来 24 周的订购和转运方案时,以新的产能\(P'\)为基础,结合企业的生产需求、成本约束等条件,建立优化模型 。目标函数可以设定为总成本最小,包括采购成本、运输成本等 。约束条件则包括供应商的供货能力限制、转运商的运输能力限制、企业的库存要求以及产能要求等 。例如,采购成本约束可以表示为\(\sum_{i = 1}^{24}\sum_{j = 1}^{n}c_{j}x_{ij}\leq C_{max}\),其中\(c_{j}\)是第\(j\)个供应商的单价,\(x_{ij}\)是第\(i\)周从第\(j\)个供应商的订购量,\(C_{max}\)是企业设定的最大采购成本 。通过求解这个优化模型,我们可以得到满足产能提升且成本最优的订购和转运方案 。
(二)代码实践
在 Python 中,我们可以借助pulp库来实现上述产能提升分析和方案制定的代码 。pulp是一个用于线性规划、整数规划等优化问题的 Python 库,它提供了简洁的语法和高效的求解器接口 。首先,安装pulp库,如果使用pip安装,可以在命令行中输入pip install pulp 。然后,进行代码编写 。假设我们已经读取了供应商的供货量、单价、转运商的运输能力、损耗率等数据 。
from pulp import LpProblem, LpVariable, LpMinimize, lpSum
# 读取供应商数据,假设数据文件为'supplier_data.csv'
supplier_data = np.genfromtxt('supplier_data.csv', delimiter = ',')
# 供应商数量
n = len(supplier_data)
# 转运商数量
m = 8
# 成本矩阵,c[j]表示第j个供应商的单价
c = supplier_data[:, 2]
# 供应商供货量矩阵,s[j]表示第j个供应商当前的供货量
s = supplier_data[:, 3]
# 转运商运输能力向量,t[k]表示第k个转运商的运输能力
t = np.array([6000] * m)
# 转运商损耗率向量,l[k]表示第k个转运商的运输损耗率,假设从另一个文件读取
loss_data = np.genfromtxt('loss_rate_data.csv', delimiter = ',')
l = loss_data[:, 1]
# 假设通过分析得到供应商的供货增量和转运商的运输能力提升量
delta_s = np.array([1000] * n) # 示例数据,实际需根据分析确定
delta_t = np.array([500] * m) # 示例数据,实际需根据分析确定
# 定义产能提升后的生产函数
def new_production_capacity():
supply_sum = np.sum(s + delta_s)
transport_sum = np.sum((1 - l) * (t + delta_t))
return min(supply_sum, transport_sum)
new_capacity = new_production_capacity()
# 定义优化问题
problem = LpProblem("Production_Optimization", LpMinimize)
# 定义决策变量,x[i][j]表示第i周从第j个供应商的订购量
x = [[LpVariable(f'x_{i}_{j}', lowBound = 0) for j in range(n)] for i in range(24)]
# 定义转运变量,y[i][j][k]表示第i周从第j个供应商由第k个转运商运输的量
y = [[[LpVariable(f'y_{i}_{j}_{k}', lowBound = 0) for k in range(m)] for j in range(n)] for i in range(24)]
# 目标函数:最小化总成本,这里只考虑采购成本,可根据实际情况添加运输成本等
problem += lpSum(c[j] * x[i][j] for i in range(24) for j in range(n))
# 约束条件:产能约束
for i in range(24):
problem += lpSum(x[i][j] for j in range(n)) <= new_capacity
# 供应商供货能力约束
for j in range(n):
problem += lpSum(x[i][j] for i in range(24)) <= s[j]+delta_s[j]
# 转运商运输能力约束
for k in range(m):
problem += lpSum(y[i][j][k] for i in range(24) for j in range(n)) <= t[k]+delta_t[k]
# 运输关系约束
for i in range(24):
for j in range(n):
problem += x[i][j]==lpSum(y[i][j][k] for k in range(m))
# 损耗约束
for i in range(24):
for j in range(n):
problem += lpSum((1 - l[k]) * y[i][j][k] for k in range(m)) >= x[i][j]
# 求解问题
problem.solve()
# 输出结果
if problem.status == 1:
print('最优订购方案:')
for i in range(24):
for j in range(n):
print(f'第{i + 1}周从第{j + 1}个供应商订购量:{x[i][j].value()}')
print('最小采购成本:', pulp.value(problem.objective))
else:
print('未找到可行解')
在这段代码中,首先定义了new_production_capacity函数来计算产能提升后的数值 。然后,使用pulp库定义了优化问题problem,包括目标函数和各种约束条件 。目标函数是最小化采购成本,通过lpSum函数对 24 周内从每个供应商的订购成本进行求和 。产能约束确保每周的订购量不超过提升后的产能 。供应商供货能力约束保证从每个供应商的订购总量不超过其供货能力加上供货增量 。转运商运输能力约束限制了每个转运商的运输总量不超过其运输能力加上提升量 。运输关系约束保证从供应商订购的量等于通过转运商运输的量 。损耗约束确保考虑损耗后实际到达企业的原材料量满足订购量 。最后,使用problem.solve()求解优化问题,并根据求解结果输出最优订购方案和最小采购成本 。如果求解状态为 1,表示找到最优解,否则输出未找到可行解的提示 。通过以上代码实践,我们可以实现根据供应商和转运商的实际情况确定产能提升幅度,并制定相应的订购和转运方案 。
七、总结与拓展
在本次 2021 年大学生数模竞赛 C 题的探索中,我们从企业原材料订购与运输这一复杂的实际问题出发,通过深入分析题目关键信息,成功拆解并解决了四个核心问题 。从运用组合赋权和 TOPSIS 法筛选重要供应商,到构建线性规划模型制定订购与转运方案,再到多目标优化调整采购策略,以及基于生产函数模型提升产能并规划新方案,每一步都凝聚着数学建模的智慧与力量 。在解决问题的过程中,我们充分体会到数学建模不仅仅是数学知识的应用,更是将实际问题抽象化、模型化,再通过科学的方法求解并验证的系统性过程 。它要求我们具备敏锐的问题洞察力、扎实的数学基础、熟练的编程技能以及良好的团队协作能力 。通过这次竞赛题目的解析,我们不仅掌握了处理这类生产运营问题的方法,更提升了自己综合运用知识解决复杂问题的能力 。
数模竞赛的意义深远,它为我们打开了一扇通往实际应用的大门 。在竞赛中,我们所面对的题目往往来源于现实生活中的各个领域,如工程技术、经济管理、社会科学等 。通过参与竞赛,我们能够将课堂上学到的理论知识与实际问题紧密结合,真正做到学以致用 。这不仅有助于我们加深对知识的理解和掌握,还能培养我们的创新思维和实践能力 。数模竞赛还能锻炼我们的团队协作精神 。在竞赛过程中,团队成员需要分工明确、密切配合,共同攻克难题 。每个成员都有自己的专长,有人擅长数学建模,有人精通编程,有人善于文字表达 。通过团队协作,我们能够充分发挥各自的优势,实现资源的优化配置,从而提高解决问题的效率和质量 。
对于想要进一步探索数模世界的读者,可以尝试参加更多的数学建模竞赛,如美国大学生数学建模竞赛(MCM/ICM)等,接触不同类型的题目,拓宽自己的视野 。还可以深入学习一些高级的建模方法和算法,如深度学习在建模中的应用、智能优化算法的改进等 。也可以关注实际生活中的问题,尝试运用数学建模的方法去解决,不断提升自己的实践能力 。希望大家在数模的道路上不断前行,收获更多的知识和成长 。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)