
每年五一三天假对别人来说是出游黄金周对我们这群数模人来说就是一年一度的“脑力马拉松”。2025年的五一数学建模竞赛A题我是在实验室通宵地板和红牛堆里熬过来的。今天不打算晒获奖证书也不打算复述题目原文我想把这套“从拿到题目到交出完整论文”的完整流程——包括模型建立、求解器选型、论文写作节奏以及几个差点让我翻车的坑——原原本本拆给你看。这篇内容既适合第一次参赛、连A题B题题型差异都搞不清楚的新手也适合已经拿过省奖、想冲击国奖的老手。我会把重点放在“模型到底是怎样一步步建立起来的”以及“怎么在72小时实际上很多人只有60小时有效时间内把求解和写作都压线完成”这两个问题上。哪怕你没有参加本次比赛这套方法论也完全可以平移到国赛、华为杯甚至自己课设里的复杂问题。1. 拿到A题后的第一个小时先别急着建模很多人拿到题之后第一反应是打开翻译软件看英文题、然后赶紧下载数据开始跑代码。我见过太多队伍在第一天晚上就陷入了“跑出一个奇怪的数但不知道这是什么、评委怎么看待”的尴尬状态。A题在五一赛里通常是典型的主模型多问延伸结构第一步不是建模而是把题目“嚼碎”。1.1 逐句拆解题目把问题域和数据域分开无论A题这一年具体出的是交通流、能源调度还是资源分配它的题干都可以拆成两大块问题域题目想让你解决的实际问题通常包含若干关键词比如“优化”、“预测”、“评价”、“决策”。数据域给出的附件表、字段含义、数据粒度小时级还是分钟级、缺失比例。我的习惯是拿到题后在纸上画一个三列的表左列是“题面里说了要做什么”中列是“对应需要什么数据”右列是“可能的模型方向”。不要嫌这个动作笨它直接决定了你后面几天是否会被“答非所问”拖死。比如题目如果问你“设计调度方案并评估鲁棒性”那么你要做的核心工作就不是预测而是优化仿真。如果你把大部分精力花在预测上即使预测做得再漂亮也只占了20%的分数。1.2 识别问题类型这是建模选型的定盘星数模的题目翻来覆去其实跑不出几个类型。A题特别喜欢设置多问递进我的经验是第一问通常是“评价类”或“预测类”第二问往往是“优化类”后面还会跟一个开放的“综合方案类”。这里有个很实用的判断标准如果题眼里有“评价”、“排序”、“评估”、“等级”那是评价类对应层次分析、熵权法、TOPSIS、灰色关联等。如果题眼里有“未来”、“预测”、“趋势”那是预测类对应回归、时序、机器学习。如果题眼里有“最优”、“最大收益”、“最小成本”、“调度”那是优化类对应线性规划、整数规划、遗传算法、模拟退火。如果题眼同时出现“评价预测优化”那基本就是综合体你需要设计一个“主模型子模型”的框架而不是指望一个模型包打天下。今年这套A题我的队伍在第一小时就明确了主干是优化调度问题前置需要做数据特征分析和场景生成。这个判断让我们后面所有的代码和论文都围绕一个主线展开没有走偏。1.3 建立解题路线图三个问题问自己拆完题后我强制队伍里每个人各自写一份“解题路线图”只允许写半页纸内容回答三个问题整个A题我们要建的最核心模型是什么这个核心模型需要哪些输入从哪里来最终交付的结果长什么样能不能对着题目逐问对照这个方法屡试不爽。它会逼着你在第1天就把从数据到结论的链路想清楚而不是走一步看一步。路线图定好后贴在电脑屏幕上角后面几天每次跑偏了就拉回来看一眼。2. 模型建立的核心思路从一个“可解释的骨架”开始很多队伍有一个通病一开始就想上复杂的模型神经网络、深度强化学习什么都往上堆。但竞赛论文评阅人最看重的是“模型的逻辑自洽性”而不是“模型的复杂度”。我的建议是先从最简单的骨架搭起。2.1 机理模型永远是第一选择A题既然有大量的物理/工程/社会场景背景很多时候题目本身就给了很多变量之间的因果关系。比如你要优化一个调度问题调度的物理约束时间窗、容量限制、资源平衡本身就是机理。你可以用**混合整数线性规划MILP**做骨架。建模步骤大概是定义决策变量——最核心的是“做什么选择”。比如资源分配的“分配量”、路径规划里的“0-1路径变量”。写出目标函数——通常是最大化收益或最小化成本。收益和成本怎么量化要回到题目给的指标。列出约束条件——用数学式子描述客观限制比如供需平衡、设备容量、时间顺序、逻辑互斥。这里有一个关键建议所有变量和约束都要有单位、有量纲意识。很多队伍写出来的约束方程连两边单位都对不上评阅人一眼就能看出是硬凑的。举一个通用的例子假设我们在做一个电力调度或者产能调度的问题骨架可以写成import pulp # 定义问题 prob pulp.LpProblem(Scheduling_Problem, pulp.LpMaximize) # 决策变量x[i][j] 表示第i个时段第j台设备的生产量 x pulp.LpVariable.dicts(production, ((i, j) for i in range(24) for j in range(5)), lowBound0, catContinuous) # 目标函数最大化总收益 sum(价格 * 产量) - sum(成本 * 产量) prob pulp.lpSum(price[i] * x[i, j] - cost[j] * x[i, j] for i in range(24) for j in range(5)) # 约束每个时段总需求必须满足 for i in range(24): prob pulp.lpSum(x[i, j] for j in range(5)) demand[i] # 约束每台设备有容量上限 for i in range(24): for j in range(5): prob x[i, j] capacity[j] # 求解 status prob.solve() print(状态:, pulp.LpStatus[status]) print(最优收益:, pulp.value(prob.objective))这段代码是所有MILP问题的“hello world”骨架。你不用管具体领域把这个骨架里的price、cost、demand、capacity换成题目的实际语义就已经完成了50%的建模工作。2.2 当机理不完整时用数据驱动模型补位A题经常会遇到“有些变量之间的关系根本不明确”的情况。这时候你就需要数据驱动模型来补位。但要注意补位模型只能用在局部不能作为主干。举个例子题目给了一堆历史数据让你做某件事的效益预测但又要求你基于预测结果做一个优化决策。那么合理的框架是先用机器学习模型预测比如XGBoost、随机森林、或者简单的时间序列模型。把预测结果作为参数输入到优化模型中。再做敏感性分析看看预测误差如何影响优化结果。这就叫“预测决策”两阶段模型。在两阶段模型里第一阶段的误差如果不做传播分析整个框架的可信度就要打折扣。所以我在论文里专门加了一节“预测误差传播分析与鲁棒性检验”这实际上就是我们的加分项。2.3 评价模型别只会层次分析法第一问如果让你评价多个方案/多个对象大部分人第一反应就是层次分析法AHP。但AHP的主观性很强评阅人看了几百份千篇一律的AHP也会审美疲劳。我个人比较推荐的组合是先做熵权法/CRITIC法做客观赋权。再做TOPSIS/灰色关联度做综合排序。有数据可以深度学习或者模糊综合评价的时候适当做一个横向对比。这样既能体现你的客观性又能体现你对不同方法的理解和对比能力。而“方法之间的比较”恰恰是评委区分水平的关键参考。我在论文里画了一张“模型-输入-输出-适用性”的对照表直接告诉评委我选了三种评价方法它们分别适合解决什么情况结果互相验证。这种处理方式比单堆一个复杂模型得分高得多。2.4 模型假设要“少而关键”有些队伍为了显得严谨一口气写了20条假设把自己模型的适用面越写越小还增加了评阅人的阅读负担。我写假设的原则只有两条一是假设必须是为了简化计算且符合客观实际的二是每个假设如果不成立必须要有补充方案。通常我的模型假设控制在6到8条每一条都紧紧围绕题干设定。某些假设比如“忽略设备启动时间”后面我会在模型改进中讨论如果去掉它会如何这样展示出你作为工程师的完整性思维。3. 求解器与代码实现的关键细节模型写出来了接下来就是最让人头疼的部分怎么把它解出来。3.1 优化模型的求解器选型如果骨架是MILP我推荐的主力工具是pulp适合教学和中小规模、scipy.optimize.milp新版已经支持混合整数问题和gurobi学术版免费性能最强但需要申请license。如果是非线性规划可以考虑scipy.optimize.minimize。选型背后的逻辑是问题规模小几百个变量优先用pulp社区教程多、报错友好、安装简单。问题规模中等数千到数万变量上gurobi它的分支定界算法和lazy constraint机制在竞赛场景下能扛住大部分压力。大规模非线性/组合爆炸问题写遗传算法或模拟退火不要指望精确解。我特别强调一下不要一上来就写遗传算法。遗传算法这类启发式算法的最大问题是“没有最优性保证”而MILP求解器能告诉你什么是全局最优。只有在精确解实在解不动、或者问题是纯组合爆炸型的时候才用启发式。你在论文里说“用遗传算法找到了全局最优解”这句话从数学上就是错的。3.2 数据处理阶段的“隐形时间黑洞”五一赛只有72小时我见过将近20%的队伍直接栽在数据处理上。这里说一个最容易被低估的问题真实竞赛数据大量存在缺失值和异常值但很多新手只是粗暴地删掉或者补零。我的建议是建立一套“数据清洗标准流程”逐字段统计缺失率——缺失率超过30%的字段考虑是否保留。缺失值用时间插值或同类均值填充不要用全局均值后者会严重破坏时序特征。异常值用3σ准则或IQR识别结合业务逻辑确认是否真的是异常。保留一份“清洗前”和“清洗后”的对比统计表这个表在论文的“数据处理”一节是很好的可视化素材。这一步处理的严谨程度会在论文的“模型假设与预处理”章节体现得特别明显也是拉开论文档次的关键。代码层面可以这样写import pandas as pd import numpy as np def clean_data(df): df df.copy() # 1. 处理缺失值按列的时间顺序插值 df df.interpolate(methodlinear, limit_directionboth) # 2. 3σ异常值处理 for col in df.select_dtypes(include[np.number]).columns: mean df[col].mean() std df[col].std() lower, upper mean - 3*std, mean 3*std df.loc[(df[col] lower) | (df[col] upper), col] np.nan df df.interpolate(methodlinear, limit_directionboth) return df3.3 敏感性与鲁棒性分析到底怎么做模型跑出一个最优解这只是开始。评委最常问的一个问题是“你的模型对参数变化稳定吗”所以敏感性分析必须做而且要有针对性地做。我的做法是挑出模型里3到5个关键参数比如需求预测值、成本系数、约束条件的上下限将其在±20%范围内以5%为步长做扰动统计目标函数值的变化百分比。如果目标函数只变化了几个百分点说明鲁棒性好如果变化剧烈就说明模型对参数过于敏感需要在论文里重点解释原因。画一个**“参数扰动-目标值变化”热力图**或曲线图放在论文“模型检验”部分是非常抢眼的亮点。3.4 代码组织三天后你必须改得动自己的代码竞赛熬夜效率下降时你能记住的只剩代码结构。我强烈建议在第一天就建好这样的目录/ project / data # 原始数据与清洗后数据 / models # 各问对应的建模代码 / figs # 所有输出图片 / utils # 公共函数 / docs # 论文草稿与参考文献 main_q1.py main_q2.py main_q3.py变量命名也请遵守“见名知义”的原则。别小看这些工程习惯我见过有队伍最后交论文时找不到自己跑出结果的那份代码那是真的欲哭无泪。4. 论文写作的节奏与技术细节建模和求解占掉比赛从严的前两天最后一天或者最后20小时基本要全压给写作。这里有个残酷的现实评阅人看的是论文不是你的代码和模型。你做了一百分的模型论文只表达出六十分那你的最终得分的上限也就是六十分。4.1 先写摘要框架再写正文我写论文的习惯和多数人不一样先写摘要的骨架。这个骨架包括四个部分本文针对XX问题一句话概括问题背景。构建了XX模型一句话概括核心方法创新点。求解得到XX结果晒出核心数值。通过XX检验模型具备良好鲁棒性收尾。摘要骨架写完后面就是往里面填肉。这样到比赛最后一天即使时间再紧我的摘要也已经有了七成完成度剩下的只是微调。不要在最后两小时才动笔写摘要——那是全篇最关键的文字最需要雕琢也最忌仓促。4.2 模型建立与求解这章的“三段式”写法标题里既然有“模型建立与求解”这一章就是全篇的脊梁骨。我写的每一个模型段落都会严格遵循三段式第一段写模型动机——为什么用这个模型结合题目背景说不要空谈。第二段写变量定义和公式推导——所有符号逐一说明公式用Word公式编辑器或LaTeX写规范。第三段写求解方案和结果展示——用了什么算法/求解器收敛到什么程度得到什么量级的结果。举一个真实感受很多新手在写模型的时候只写公式不写“符号说明表”让评委自己去猜参数含义这是大忌。我的一般做法是每一个核心模型都配一张符号表符号、含义、单位、取值来源四列。这一张表下来论文可读性完全提升一个层级。4.3 图表数量与质量宁缺毋滥竞赛论文的页数一般不超过25到30页。有些队伍贴了满屏的大图但信息密度极低。我的经验是全篇有效图表控制在12到18张之间每张图必须能独立说明一个问题。写“图”的时候图题不要写“结果图”这种废话而要写“不同方案在不同需求水平下的总成本对比”。看图题就知道图在讲什么是提升论文专业感最常见的便宜手段。我还用了一个非常土但有效的招所有图片统一字体、统一配色、统一坐标轴风格。别让三张图看起来像三个人画的。排版统一性好评委印象分会明显上浮。4.4 模型检验与改进不要只写“误差很小”模型检验部分我见过最常见的写法是“误差在可接受范围内说明模型有效”。这句话说了等于没说。检验部分要有血有肉用绝对百分比误差MAPE、**均方根误差RMSE**等量化指标给出具体数值。做残差分析画出残差图判断是否存在系统性偏差。与**基础模型均值模型、线性回归**做对比显示出你的模型改进幅度。做灵敏度/鲁棒性分析参考上一节的方法。模型改进部分则要诚实列出当前模型的局限性并给出一个“如果不考虑计算量你会怎么做”的展望方案。评委最怕看到“本研究模型完美无缺”的态度。一个思路清晰的团队敢于承认不足并提出替代方案这本身就是建模能力的体现。4.5 附录与源码你的最后加分项近几年竞赛评审逐渐重视代码和数据的可复现性。论文主文之后的附录我一般放三样东西核心代码片段优化模型的构建代码、关键算法伪代码。数据清洗前后对比表。核心结果统计表各问结果汇总、敏感分析的数值表。这会给评委留下“这个队伍很严谨”的印象。很多参赛队伍代码就是一坨有个能跑就行的状态回头放在附录里自己都不好意思。我的建议是至少保证核心结果对应的那一段代码是干净、注释充分、可读性强的。5. 常见翻车点与避坑经验真实教训回顾下面这部分是拿真金白银换来的教训。这几个坑希望大家不要踩5.1 论文提交不上的噩梦每年竞赛都有队伍在最后截止前半小时疯狂刷新提交页面结果卡住。五一赛的提交系统在截止前一小时网络会拥堵实力再强提交失败也是零分。我的铁律是在截止前至少3小时完成论文最终版并提交成功之后只做“查看成功状态”的动作不再改动并重新提交。如果条件允许打印一份纸质备份以备最坏情况。提交前一定确认文件名按竞赛要求命名通常有统一规则PDF文件体积在系统限制内一般不超过20MB每一问的答案是否都已经体现在目录和页码中。5.2 AI工具的使用边界与自查这两年AI辅助写作在数模竞赛里越来越普遍但很多队伍因为AI率过高被通报。我的经验是AI可以用但要明确边界。数值计算、代码调试、语法优化随便用论文正文的润色可以用但要人工逐句审。最危险的操作是直接把AI生成的分析段落原样粘贴到论文里那是拿整队的比赛资格开玩笑。如果竞赛要求提交AI使用报告/自查表务必在比赛结束前留出至少1小时逐项填写。不要比赛快结束了才想起这个表到时候手忙脚乱。5.3 时间分配72小时的情绪管理我见过很多队伍第一天通宵拼进度结果最后一天全体趴窝。我们的节奏是第一天上午统一拆题、定路线、分工下午开始数据处理和代码框架。第一天晚上到第二天中午集中火力解决第一问和第二问的模型与求解。第二天下午到晚上解决第三问/综合问题同时由论文手开始写摘要和第一二章。第三天全天集中写作、画图、做检验、排版、查重、准备附件。最后留出3小时作为“机动时间”用来应对突发状况跑崩的模型、重新画的图、修改的公式。第三天的情绪管理也很重要这天最容易吵架也最容易自我怀疑。我坚持一个原则“先完成再完美”。哪怕某个模块你觉得不够好只要整体闭环了就先向前走。论文和模型的完美主义留给赛后再说。5.4 分工与协作写论文的从第一天就开始干活很多队伍是前两天全是建模和编程的人在卷论文手无所事事刷手机第三天突然让论文手一天写出二十页。这不合理。论文手第一天就要参与拆题理解模型思想先搭建论文框架第二天直接开始写前置章节第三天才有精力打磨核心章节的表述。代码手和建模手也要养成“边写模型边做笔记”的习惯。这个模型的每个变量叫什么、每个约束条件是哪个现实的映射随手记下来最后汇总给论文手。这样能把整理符号说明表和模型假设的时间从5小时压缩到1小时。6. 竞赛之外的长尾收获比赛结束后两天我重新审视了一遍我们提交的论文和代码发现那些“当时觉得只是迫于时间做的粗糙选择”其实隐藏着几条可以继续深挖的线。这也是我想说的最后一点数模竞赛的价值早就超出了那个分数本身。通过一次完整的A题训练你会逼自己掌握一套从问题定义、数据清洗、机理建模、算法求解到论文写作的完整工程闭环。这套闭环能力在你日后做课设、发论文、进企业做项目时全部都用得上。我看到过很多人比赛结束就删数据、删代码我强烈不建议把代码整理好上传到代码托管平台把数据和分析结论归档到网盘过一两个月再回看你会惊讶于当时的自己已经具备的专业敏感度。今年的A题已经结束了无论你拿了什么奖那个五一假期里通宵过的你、争论过的你、跑到提交系统关闭前最后一刻的你都已经比三天前的自己强了一大截。备赛明年国赛的时候翻出这篇流程按着步骤再来一遍——你会发现轻舟已过万重山。