数学建模竞赛C题:动态优化与滚动时域决策实战解析
2026/8/28 20:21:37 网站建设 项目流程

1. 赛题核心与破题思路拆解

2021年全国大学生数学建模竞赛C题,题目是“生产企业原材料的订购与运输决策”。这题一出来,很多队伍都懵了,感觉像是个供应链管理或者运筹学的题,但又和传统的库存模型不太一样。我当时带了几支队伍,自己也深入研究了一下,发现这道题的精髓在于它构建了一个多周期、多供应商、需求不确定且存在损耗的复杂决策环境。它不是让你套一个经典的EOQ(经济订货批量)模型就完事的,它逼着你去思考,在现实生产约束下,如何动态地平衡“订购成本”、“库存成本”、“缺货损失”和“运输成本”这几座大山。

简单来说,题目给了你一家生产企业,每周需要向供应商订购原材料,供应商不止一家,每家供货能力和运输成本还不同。原材料运到企业后,并不是立刻全部投入生产,而是先进入仓库。生产部门每周从仓库领料,但这个领料量(即生产需求)是波动的、预测出来的,不是定值。更麻烦的是,仓库里的原材料不是“永葆青春”的,放久了会变质,有个折算比例,相当于价值损耗。你的任务就是:根据未来24周(附件提供了前8周的实际数据)的需求预测,制定每一周向每一个供应商的订购量,以及选择相应的运输方式,目标是使企业的总成本(订购费+库存费+缺货损失+运输费)最低。

所以,破题的关键在于建立一套动态决策模型。你不能只看一周,必须考虑未来多周的需求趋势和库存状态;你不能只订一家,必须权衡各家供应商的价格和运能;你不能无视损耗,必须让库存周转起来。很多队伍一开始就陷入了“精确求解”的误区,试图搞出一个能一次性求出24周最优解的超级模型,结果要么模型过于复杂无法求解,要么忽略了问题的动态性。我的思路是:将其分解为“预测-决策-优化”三个核心模块,采用“滚动时域优化”的策略进行求解。先基于历史数据预测未来需求,然后以未来几周为窗口,在窗口内进行优化决策,执行第一周的决策后,时间滚动到下一周,用新的实际数据更新预测和状态,再优化下一个窗口,如此循环。这种方法在学术上叫Model Predictive Control (MPC),在工程上非常实用,既能应对不确定性,又保证了决策的可行性。

2. 需求预测模块的构建与实操

题目只给了前8周的实际供货量和企业的周产能,需求是隐含的。我们需要预测的是未来24周每周的生产需求(即从仓库的领料量)。这是所有决策的起点,预测不准,后面优化得再好也是南辕北辙。

2.1 数据理解与预处理

附件中的数据是关键。你需要仔细分析“供应商的供货数据”和“企业的产能数据”。供货数据反映了供应商的历史表现和可能的季节性,但注意,供货量不等于企业的需求,它受企业订单量(即你的决策)和供应商产能上限的双重影响。企业的周产能是一个重要的约束,生产需求不可能超过最大产能,这为预测提供了一个上限。

第一步是数据清洗和可视化。画出前8周各供应商的供货量曲线、企业总库存变化曲线。通过库存变化,我们可以反推每周的实际消耗量(即需求):本周消耗量 = 上周末库存 + 本周到货量 - 本周末库存。这里就涉及到对“损耗”的理解。题目说库存原材料每周会有价值折算,在预测需求时,我们可以先忽略损耗的具体计算,因为损耗影响的是成本模型,而不是需求本身。我们反推的是物理上的“领出量”。

2.2 预测模型的选择与融合

对于这种时间序列预测,常见方法有移动平均、指数平滑、ARIMA模型等。但这里只有8个数据点,传统时间序列模型很难训练。因此,融合多种简单方法,并结合业务逻辑进行判断是更稳妥的策略。

  1. 趋势外推法:计算前8周平均周消耗量,作为未来需求的基线。如果数据有轻微上升或下降趋势,可以加上一个简单的线性趋势项。
  2. 周环比法:观察数据是否呈现以“周”为周期的波动。比如,是否每月的最后一周需求较高?虽然数据少,但可以结合附件中可能隐含的“产能利用率”信息进行推测。
  3. 基于产能的约束调整:预测出的周需求值,绝对不能超过题目给出的周最大产能。这是一个硬约束,必须对预测结果进行截断处理。
  4. 不确定性处理:预测不可能100%准确。在优化模型中,我们需要考虑预测误差带来的风险。一个实用的技巧是,生成三种需求情景:基准情景、乐观情景(需求下调10%)、悲观情景(需求上调10%)。后续的优化可以在多情景下进行,或者采用鲁棒优化的思想,使决策方案在多种可能的需求下表现都相对较好。

实际操作中,我建议队伍用Excel或Python(Pandas库)先做一遍数据反推和可视化。然后用一个加权组合的方式生成最终预测:最终预测需求 = a * 移动平均值 + b * 最近一周值 + c * 产能约束调整值,其中a, b, c是根据数据特征设定的权重,总和为1。例如,如果数据很平稳,a可以设大些;如果最近一周有特殊变化,b可以设大些。

注意:切忌在预测环节过度复杂化。数学建模竞赛时间有限,预测模块是为决策优化服务的,只要预测结果合理、能自圆其说,并且在论文中清晰阐述你的预测方法和依据,就能拿到相应的分数。把主要精力放在后面的优化模型上。

3. 动态优化决策模型详解

这是整个赛题最核心、最见功力的部分。我们需要建立一个数学模型,在每一决策点(每周初),根据当前库存、在途物资、未来需求预测,来决定本周向各供应商订多少货,以及选择何种运输方式。

3.1 模型要素定义

首先,明确定义以下要素,这是建模的基础:

  • 决策变量x_{i,t}表示第t周向供应商i的订购量;y_{t}表示第t周选择的运输方式(可能是一个0-1变量,例如0代表普通运输,1代表加急运输,具体看题目附件说明)。
  • 状态变量I_t表示第t周末的库存水平。它是连接前后周期的纽带,满足状态转移方程:I_t = I_{t-1} + Σ x_{i,t- L_i} - D_t + S_t。这里L_i是供应商i的运输提前期(可能为0或1周),D_t是第t周的预测需求,S_t是可能的损耗量(与I_{t-1}相关)。
  • 成本项
    • 订购成本:可能包含固定订购费(只要订货就产生)和可变采购费(与订货量成正比)。
    • 运输成本:与运输方式和总运量相关,可能是一个分段函数或固定费率。
    • 库存持有成本:与期末库存I_t成正比。注意,如果题目明确了损耗是价值折算,那么库存成本的计算基数是折算后的库存价值。
    • 缺货成本:如果实际需求大于(可用库存+到货),则产生缺货。缺货成本通常很高,是惩罚项。在模型中,可以引入缺货量B_t作为辅助变量,成本与B_t成正比。

3.2 滚动时域优化框架

直接建立24周的整体优化模型,变量和约束太多,求解困难,且不符合“每周做一次决策”的动态过程。因此,滚动优化是更合理、更可行的框架。

  1. 设定优化窗口长度N:例如N=4周或N=6周。这意味着,我们在第T周做决策时,只考虑未来N周(第T周到第T+N-1周)的情况。
  2. 构建窗口内的优化模型:以第T周为起点,未来N周的需求预测(D_T, D_{T+1}, ..., D_{T+N-1})是已知的输入。当前库存I_{T-1}是已知初始状态。我们建立一个以未来N周总成本最小化为目标的数学规划模型。
    • 目标函数:Min Σ (第T到T+N-1周的各项成本之和)。
    • 约束条件
      • 库存平衡约束(核心)。
      • 供应商供应能力约束(附件中每家供应商可能有周最大供应量)。
      • 企业仓库容量约束(库存上限)。
      • 运输方式选择约束(可能限制每周只能选一种)。
      • 非负约束、整数约束(如果订购量必须为整数)。
  3. 求解与滚动:求解这个N周的优化问题,得到最优解序列:x_{i,T}, x_{i,T+1}, ..., x_{i,T+N-1}。但是,我们只取第一周的决策结果(即x_{i,T}y_T)作为本周的实际执行方案。
  4. 状态更新与窗口前移:执行完第T周的决策后,进入第T+1周。此时,我们会“知道”第T周更准确的需求(如果题目有反馈机制,否则仍用预测),库存状态更新为I_T。然后将优化窗口向前移动一周(从T+1周到T+N周),用更新后的状态和新的需求预测(可能重新预测或沿用),重复步骤2-3,进行下一轮的优化决策。

这个框架完美模拟了企业实际的滚动计划流程,模型在每一轮只需求解一个规模较小的N周问题,计算量可控。在论文中,需要画出清晰的滚动优化流程图。

3.3 模型求解工具选择

这个优化模型通常是一个**线性规划(LP)混合整数线性规划(MILP)**问题(如果运输方式选择是0-1变量)。推荐使用以下工具:

  • LINGO:专为优化设计,语法简单,求解速度快,非常适合数模竞赛。对于线性/整数规划问题,代码非常简洁。
  • MATLAB + Optimization Toolboxlinprog函数用于线性规划,intlinprog函数用于混合整数线性规划。适合习惯MATLAB的队伍。
  • Python + PuLP / CVXPY:PuLP库建模非常直观,类似自然语言,易于调试。CVXPY则更加强大。Python的优势是方便与数据预处理、结果可视化整合。

我强烈建议队伍在练习阶段就选定一个工具并熟练掌握。比赛时,先用手工简化数据(比如只考虑2个供应商、4周)把整个模型流程跑通,确保模型逻辑、代码没有错误,然后再代入全部24周、多个供应商的真实数据运行。这能极大避免最后一天发现模型根本算不出来的灾难。

4. 核心环节实现:以Python+PuLP为例

这里我以一个简化版为例,演示滚动优化的核心代码逻辑。假设有2个供应商,运输提前期均为1周,优化窗口N=4周。

import pulp import pandas as pd import numpy as np # 假设我们已经有了未来M周的需求预测列表 forecast_demand[M] # 假设初始库存为 I0 # 定义供应商参数:成本,供应上限等 suppliers = { 'A': {'cost_per_unit': 10, 'max_supply': 500, 'lead_time': 1}, 'B': {'cost_per_unit': 12, 'max_supply': 300, 'lead_time': 1} } holding_cost = 0.5 # 每周每单位库存持有成本 shortage_cost = 20 # 每周每单位缺货成本 warehouse_capacity = 1000 def rolling_optimization(start_week, current_inventory, horizon=4): """ 执行一次滚动优化 :param start_week: 当前周次 (T) :param current_inventory: 当前周初库存 I_{T-1} :param horizon: 优化窗口长度 N :return: 本周应向各供应商订购的量 (dict) """ # 1. 获取未来N周的需求预测 demand_forecast = forecast_demand[start_week: start_week + horizon] # 2. 创建PuLP问题 prob = pulp.LpProblem(f'Week_{start_week}_Rolling_Optimization', pulp.LpMinimize) # 3. 定义决策变量 (窗口内每周、每个供应商的订购量) order_vars = pulp.LpVariable.dicts('Order', ((s, w) for s in suppliers for w in range(horizon)), lowBound=0, cat='Continuous') # 定义库存和缺货变量 inventory_vars = pulp.LpVariable.dicts('Inv', range(horizon+1), lowBound=0) # 包含第0周(期初) shortage_vars = pulp.LpVariable.dicts('Short', range(horizon), lowBound=0) # 4. 设置初始库存 prob += inventory_vars[0] == current_inventory # 5. 定义目标函数:最小化总成本(订购成本 + 库存成本 + 缺货成本) # 订购成本 order_cost = pulp.lpSum([order_vars[s, w] * suppliers[s]['cost_per_unit'] for s in suppliers for w in range(horizon)]) # 库存持有成本 holding_cost_total = pulp.lpSum([inventory_vars[w] * holding_cost for w in range(1, horizon+1)]) # 缺货成本 shortage_cost_total = pulp.lpSum([shortage_vars[w] * shortage_cost for w in range(horizon)]) prob += order_cost + holding_cost_total + shortage_cost_total # 6. 添加约束 for w in range(horizon): # 库存平衡约束 (考虑提前期) # 本周到货 = sum( lead_time周前的订单 ) arrivals = pulp.lpSum([order_vars[s, w_prev] for s in suppliers for w_prev in range(horizon) if w_prev + suppliers[s]['lead_time'] == w]) # 平衡方程: 期末库存 = 期初库存 + 到货 - 需求 + 缺货 prob += inventory_vars[w+1] == inventory_vars[w] + arrivals - demand_forecast[w] + shortage_vars[w] # 供应商供应能力约束 for s in suppliers: prob += order_vars[s, w] <= suppliers[s]['max_supply'] # 仓库容量约束 prob += inventory_vars[w+1] <= warehouse_capacity # 7. 求解 prob.solve(pulp.PULP_CBC_CMD(msg=False)) # 8. 提取本周(窗口第一周)的决策 current_orders = {} if pulp.LpStatus[prob.status] == 'Optimal': for s in suppliers: current_orders[s] = order_vars[s, 0].varValue print(f"Week {start_week} optimal orders: {current_orders}, Total Cost: {pulp.value(prob.objective)}") return current_orders else: print("Optimization failed!") return None # 主循环模拟24周滚动决策 I = initial_inventory orders_schedule = [] for week in range(24): # 假设总共决策24次 week_orders = rolling_optimization(week, I, horizon=4) if week_orders: orders_schedule.append(week_orders) # 模拟实际执行:更新库存状态(这里简化,假设需求等于预测,且无损耗) # 实际中,这里应该用更复杂的模拟器来更新状态 total_arrival_this_week = sum([week_orders[s] for s in suppliers]) # 简化:假设提前期=0 I = I + total_arrival_this_week - forecast_demand[week] I = max(I, 0) # 库存非负 else: break

这段代码提供了一个完整的滚动优化骨架。在实际比赛中,你需要根据附件数据填充参数,并完善状态更新逻辑(特别是考虑运输提前期和损耗)。模型的目标函数和约束也需要根据题目描述进行细化,例如加入固定订购费、运输方式选择等。

5. 结果分析与模型检验

得到24周的订购与运输方案后,工作只完成了一半。如何检验你的方案好坏?如何在论文中展现模型的优越性?这是拿高分的关键。

5.1 方案的成本核算与敏感性分析

你需要设计一个模拟器。这个模拟器不依赖于你的优化模型,它就像一个“上帝视角”的沙盘,严格按照你制定的24周方案,结合真实的(或你认为合理的)需求序列、损耗规则,去计算最终发生的总成本。这个成本才是评价方案优劣的最终标准。

  • 基准情景分析:用你预测的“基准需求”序列运行模拟器,得到基准总成本。
  • 敏感性分析:这是亮点!改变关键参数,观察方案的成本变化。
    • 需求波动:将需求上下浮动10%、20%,重新模拟。你的方案成本增加了多少?这体现了方案的鲁棒性。
    • 成本参数变化:例如,运输成本上涨10%,库存成本上涨10%,对总成本的影响有多大?这能说明方案对不同成本结构的适应能力。
    • 预测误差分析:故意在你的预测中加入随机误差,模拟预测不准的情况,看看滚动优化模型相比“静态一次性优化”模型,是否表现更稳定。

5.2 模型对比与评价

在论文中,你不能只说“我的模型很好”,要通过对比来证明

  1. 对比策略一:经验策略。设计一个简单的基准策略,例如:

    • 固定订货点策略:当库存低于某个安全库存时,按固定量订货。
    • 等量订购策略:每周订购相同的量,等于平均需求。 用你的模拟器计算这些简单策略的成本,你的优化模型应该能显著降低成本(例如降低15%-30%)。这个对比能直观展示优化带来的价值。
  2. 对比策略二:不同优化窗口长度。尝试N=3, N=4, N=6,比较它们最终的总成本和计算时间。你会发现,窗口太短(N=3)可能目光短浅,窗口太长(N=6)计算量增大但收益不明显。在论文中分析并给出你选择N=4(举例)的理由,这体现了你对模型参数的深入思考。

  3. 模型优缺点与推广:诚实地讨论你的模型假设(如需求预测是准确的、损耗模型是线性的)在什么情况下可能不成立。简要说明模型可以如何推广到更复杂的情况,比如供应商有最小起订量、存在价格折扣、运输方式更多样等。这展示了你的思维高度。

6. 论文写作与常见陷阱规避

数学建模竞赛,论文是唯一的评分依据。模型再好,表达不清也白搭。

  • 摘要:重中之重!必须精炼地说明“针对什么问题,建立了什么模型,采用了什么方法(特别是滚动优化框架),得到了什么方案(主要结论),进行了什么分析(敏感性分析),结果如何(成本降低了多少)”。避免在摘要中出现公式和细节。
  • 模型假设:清晰列出。例如:“假设每周初做决策并立即下单”、“假设运输提前期已知且固定”、“假设需求预测误差在一定范围内”等。合理的假设是简化问题的前提。
  • 符号说明:用三线表格清晰列出所有变量、符号及其含义。这是专业性的体现。
  • 模型建立:分小节阐述。对应我们上面的模块:6.1 问题分析与整体框架;6.2 需求预测模型;6.3 滚动优化决策模型(包含目标函数、约束条件、状态转移方程);6.4 模型求解方法。
  • 模型求解与结果:给出核心的求解流程(代码框图或伪代码),展示关键结果(例如,用表格列出24周的订购计划,用图表展示库存水平变化趋势)。
  • 模型检验与灵敏度分析:单独成节,详细展示对比实验和敏感性分析的结果,用图表(如柱状图、折线图)直观呈现。
  • 优缺点与推广:客观评价,体现思维的全面性。

常见陷阱与避坑指南

  1. 忽略损耗或处理错误:损耗是本题特色。一定要在库存状态方程和库存持有成本计算中正确体现。如果损耗是比例折算,那么计算库存成本时,库存价值是递减的。
  2. 混淆决策周期:题目要求“每周制定”计划,但你的模型输出的是未来24周固定计划,这不符合题意。必须体现“滚动”、“动态调整”的过程。
  3. 模型求解失败:一开始就用完整数据建模求解,容易因规模大或模型有误而卡死。务必先用极小规模数据(2周,1个供应商)调试通所有逻辑和代码。
  4. 论文只有模型没有结果:花了大量篇幅描述复杂的模型,但结果部分只有一句话“我们求解得到了最优方案”。必须将核心的决策方案(订购量表)和关键的绩效指标(成本变化图、库存曲线)清晰地呈现出来。
  5. 敏感性分析流于形式:只说“模型对参数变化不敏感”,但没有数据支撑。必须设计具体的对比实验,用数字说话。

这道C题考察的是将实际问题转化为数学模型,并设计有效算法求解的综合能力。它没有标准答案,关键在于你的建模逻辑是否清晰、求解过程是否合理、结果分析是否深入。抓住“动态”、“滚动”、“多目标权衡”这几个核心,建立一个稳健可解的模型,并配上一份逻辑严密、图表清晰的论文,就能取得非常不错的成绩。最后提醒一点,团队分工要明确,一个人主攻模型和算法,一个人主攻编程实现,一个人主攻论文写作和数据分析,三者要紧密配合,定期同步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询