
简介2022年五一数学建模竞赛A题血管机器人订购与学习赛题的二等奖获奖论文来自成都理工大学团队全文基于MATLAB实现。资源为一份PDF版完整论文共1个文件大小约703KB目前已有1255人学习浏览。论文围绕血管机器人订购问题综合运用动态规划、多周期折扣订购模型、最优订购控制算法与时间序列预测等方法依次求解了1-8周、1-104周以及考虑损毁、折扣和应急购买等场景下的最低运营成本订购方案并给出状态转移方程、购买量结果和运营成本对比。例如问题一最低运营成本为7625元问题二需购买882个容器艇和3836个操作手。对准备数学建模竞赛的读者而言尤其是遇到设备订购、库存优化或动态规划类赛题时可参考其问题分析、模型构建和结果呈现方式文中基于ARIMA的需求预测思路也可迁移至其他预测任务适合作为竞赛备赛和论文写作的参考资料。 2022年五一赛A题“血管机器人订购与学习”我们拿了二等奖队伍来自成都理工全程用MATLAB完成。说实话这个题放在那一年所有赛题里不算最难但特别考察“把一个实际问题拆成能算的模型”的能力。现在回头看我们能在三天两夜里稳定拿到二等奖靠的不是堆模型数量而是把“订购”和“学习”两条主线拎得足够清楚。这篇就从头复盘一下我们的完整思路、建模过程、MATLAB实现细节还有踩过的坑给之后准备数学建模的同学做个参考。1. 赛题回顾与破题思路1.1 题目到底在问什么先说背景。血管机器人可以简单理解成一种微小型医疗机器人能在血管网络里游动完成药物靶向递送、血栓清理这类任务。实际场景里要面对两个很现实的问题一是买多少台机器人、怎么配置才能兼顾成本和覆盖能力二是机器人进入血管分叉之后怎么自主判断该往哪条支路走不能每次都靠人工遥控。2022年五一赛A题把这两个问题合在一起分成了若干个小问。第一问核心是血管网络拓扑分析第二问核心是机器人订购方案优化第三问核心是让机器人在未知网络里通过“学习”找到目标点。这题目设置其实是刻意引导我们分块处理的先理解网络结构再安排资源最后用算法让单个机器人具备决策能力。拿到题目以后我们没有急着建模型而是花了大半天把题目里给的图和数据格式吃透。这一步非常重要因为A题的数据往往不是现成的标准表格更像是某种简化过的医学影像或网络抽象。我们当时把数据读进MATLAB逐个节点核对连通关系确认哪些是分叉点、哪些是末端、哪些节点之间有双向通道才敢开始设计模型。1.2 我们的第一版思路拆成三个子问题整个赛题可以被拆成三个独立又关联的子问题这也是我们最终论文的基本结构。第一个子问题给出一张血管网络图要求识别出关键路径、分叉结构和末端节点并计算相关指标。我们没有复杂化直接用图论工具把网络存成邻接矩阵用节点度判断分叉点用Dijkstra算关键路径长度用连通性判断末端节点集合。这套操作在MATLAB里非常顺。第二个子问题给定不同类型的血管机器人每种有不同成本、续航、通过分叉的能力在预算或任务约束下决定买哪些机器人、各买多少台。这本质上是一个整数规划问题。我们用MATLAB的intlinprog求解把目标函数设为总成本最小约束覆盖网络所有关键节点、至少满足一个重要任务的时效要求。第三个子问题让机器人自己学会从起点到达目标点。我们把血管网络看作一个图环境每个节点是状态机器人在节点上的动作是选择某一条相邻边。用Q-learning做强化学习训练让机器人通过不断试错学会“在哪个节点该往哪走”的策略。这个部分做出来以后效果非常直观训练完成后画出来的路径和Dijkstra最优路径几乎重合。提示拆题时一定要把“数据读取与预处理”当成独立任务。我们实际写代码的时间里数据清洗和结构化花了接近一个白天但后面所有模型都建立在干净的图结构上值回票价。2. 核心模型搭建与算法选型2.1 订购优化模型整数规划是主框架机器人的订购问题我们建了一个混合整数线性规划模型。参数方面假设有m种机器人每种机器人的单价是c_j数量是x_j非负整数续航能力是r_j能通过的边数上限单台覆盖能力是k_j单位时间内能访问的关键节点数。约束条件包含三部分预算上限sum(c_j * x_j) B关键节点覆盖要求sum(k_j * x_j) N_cover至少有一种具备长续航能力的机器人数量不低于1。目标函数是最小化总采购成本。MATLAB代码实现的核心就一段% 变量 x: 每种机器人采购数量 f c; % 成本系数 intcon 1:m; A [-k; c]; % 第一行覆盖约束取负号变成 第二行预算约束 b [-N_cover; B]; lb zeros(m, 1); ub []; % 若题目有上限再加 x_opt intlinprog(f, intcon, A, b, [], [], lb, ub);这里有个容易踩坑的点intlinprog默认全部变量都要求是整数但我们只想让数量是整数所以intcon 1:m指定整数变量范围。如果某个机器人数量可以连续变化比如租赁时长把它从intcon里去掉就行。为什么选择整数规划而不是遗传算法因为题目给的数据量不大整数规划能直接给出全局最优解而且求解速度快到可以忽略不计。遗传算法虽然听起来“高级”但在这个规模的问题上没必要反而引入随机性导致结果不稳定写论文时还要额外解释参数怎么调。2.2 学习与决策用Q-learning训练血管机器人机器人在血管里的路径决策问题本质上是一个马尔可夫决策过程。我们把血管网络抽象成图G(V,E)机器人在某个节点v只能选择一条相邻边e。目标是从起点s到达终点t。Q-learning的更新公式是经典那一套Q(s,a) - Q(s,a) alpha * (r gamma * max(Q(s,a)) - Q(s,a))其中alpha是学习率gamma是折扣因子r是即时奖励。我们设计的奖励函数很简单到达目标节点给100走入死胡同给-10其余正常移动给-1为了让机器人尽量走短路径。状态空间是节点集合动作空间是当前节点所有邻接节点的索引。MATLAB实现的核心就是一个Q表更新循环Q zeros(n, max_degree); % 按最大度初始化空动作标记为 -inf for episode 1:max_episodes s start_node; while s ~ target_node valid_actions find(adj(s, :)); % epsilon-greedy策略 if rand() epsilon a valid_actions(randi(length(valid_actions))); else [~, a] max(Q(s, valid_actions)); end s_next a; r reward(s, a); Q(s, a) Q(s, a) alpha * (r gamma * max(Q(s_next, :)) - Q(s, a)); s s_next; end end跑完以后从起点开始反复选Q值最大的动作就能得到一条路径。我们对比了Q-learning学到的最优路径和Dijkstra算出来的最短路径重合度在95%以上说明学习机制是有效的。训练过程中的奖励曲线也证明算法在收敛一开始平均回报是负数500回合后稳定在90以上。2.3 参数是怎么定下来的学习率alpha我们取0.8折扣因子gamma取0.9探索率epsilon从1.0线性衰减到0.05。这三个参数不是随便拍的而是做了小规模网格搜索。alpha如果太小收敛速度很慢对于血管网络这种状态数不超过几十的规模没必要alpha太大又容易震荡。gamma取0.9意味着机器人比较“有远见”愿意为了到达目标多走几步路考虑到血管网络里路径不会特别长这个值合理。epsilon从1衰减到0.05前期多探索保证能找到目标后期收敛到利用最优策略。注意如果网络规模变大比如节点数上百Q表会迅速膨胀这时候就要考虑用深度Q网络DQN或者函数逼近。但在赛题给定的规模下表格型Q-learning是性价比最高的方案。3. MATLAB实现细节与调试实录3.1 矩阵化思维MATLAB性能的关键MATLAB是一门“矩阵语言”写代码时有没有矩阵化思维运行效率可以差一个数量级。血管网络数据读进来后最自然的存法就是邻接矩阵adjn个节点就是n*n的二维数组。算节点度、找邻居、判断连通性全部可以基于矩阵操作完成。比如计算所有节点的度一行代码搞定deg sum(adj, 2);判断哪些是末端节点度为1也是一行end_nodes find(deg 1);如果用Python的循环思维在MATLAB里写for循环去遍历所有节点也能跑但代码会丑很多而且在大图上会很慢。我们后期优化代码时反复做了一件事把能向量化的循环全部向量化。比如Q-learning里取某一状态所有动作的Q值写成max(Q(s, :))而不是max(Q(s, 1:degree))虽然效果一样但前者更简洁也更符合MATLAB风格。3.2 核心函数与实现流程我们整个项目的代码结构分成了三层这个结构也被直接搬到了论文附录里。第一层是数据加载与网络构建函数名load_network.m返回邻接矩阵、节点坐标、类型标记。第二层是问题求解模块包括ordering_model.m整数规划、q_learning.m强化学习、dijkstra_path.m基准最短路径。第三层是结果可视化与输出plot_network.m把所有结果画在同一张图上。这里特别想说的是函数模块化不是为了显得高级而是为了调试方便。数学建模比赛时间紧张如果所有代码都堆在一个脚本里出一个bug排查半天都找不到问题在哪。我们的经验是每个模型一个独立函数输入输出写清楚测试的时候单独跑每个函数确认无误后再组装起来。有一次我们Q-learning怎么都不收敛排查了半天最后发现是adj矩阵方向存错了导致机器人只能在反方向游动。如果没做函数隔离这个问题可能要找更久。核心的Q-learning函数签名大概是这样的function [policy, Q, steps_hist] q_learning(adj, start_node, target_node, params) % adj: 邻接矩阵 % start_node / target_node: 起终点索引 % params: 结构体包含alpha, gamma, epsilon, episodes3.3 可视化与结果检验建模题不能光给数字最后一定要有直观的图。我们用了三个可视化方案来呈现结果。第一个是网络拓扑图。用MATLAB的plot(graph(adj))直接把血管网络画出来节点用圆形标记分叉点用方块标记目标点用红色五角星标记。图画出来以后论文的直观程度立刻提升。第二个是订购方案的柱状图。每种机器人采购数量用不同颜色柱体表示柱体旁边标注成本和覆盖贡献。第三个是Q-learning训练曲线。横轴是回合数纵轴是每回合累积奖励曲线一开始在负值区域震荡然后逐步爬升并稳定在高位。这条曲线是证明“学习有效”最有说服力的证据。结果检验方面我们做了一个关键验证把Q-learning学到的路径和Dijkstra最短路径做对比输出两条路径经过的节点序列计算重合率。当时的结果是几乎完全一致个别节点不同是因为有多条等长最短路径而学习算法随机选择了一条。这一点在论文里写清楚很重要说明模型不是碰巧做对了而是算法确实学到了有效的策略。4. 常见问题与排错经验4.1 MATLAB实现中的典型错误速查比赛和平时写代码不太一样没有时间慢慢查文档。我整理了一下我们用MATLAB做这个题时遇到的高频问题做成一个速查表后来复现这个题的同学也反馈特别有用。错误现象可能原因解决方案intlinprog报错“Number of variables must be an integer”f向量长度和变量个数不一致检查成本向量c是否包含所有变量确保length(f)等于x的维度Q-learning一直不收敛奖励函数设计不合理或alpha/gamma不合适调整奖励数值目标100死胡同-10普通步-1alpha取0.8gamma取0.9绘图时节点编号对不上MATLAB索引从1开始而数据文件可能是0开始读入数据后统一1或统一-1全项目保持一致矩阵维度不一致邻接矩阵不是方阵或某行度计算错误用size(adj)检查确保adj是n*n矩阵运行速度极慢for循环嵌套过深没有利用矩阵化优先用sum(adj,2)、find(deg1)这类向量化操作4.2 比赛现场遇到的两个大坑第一个坑是数据读入格式问题。题目给的网络图是一个文本文件里面是节点编号和边的连接关系。我们一开始想当然按邻接矩阵直接读结果发现文件里给出的边不是按顺序排列的而且存在重复边。这导致我们第一天的模型算出来的覆盖数量明显偏大。后来我们写了一个预处理函数先构建空的邻接矩阵逐条边填充重复边自动去重才解决了问题。第二个坑是Q-learning动作空间不统一。由于每个节点的度不一样我们用最大度初始化Q表后某些动作对某些节点是无效的。刚开始训练时没注意机器人经常会“选择”一个不存在的边导致仿真卡死。解决方案是每次选动作前先获取当前节点的有效邻居列表只在有效动作里选不能在整行Q值里选最大。4.3 给准备参赛的同学三条建议第一赛前至少把MATLAB的图论工具箱、优化工具箱、统计工具箱的基本函数过一遍不求精通但要知道有这些工具存在。比如graph对象能直接计算最短路、最小生成树这些功能在建模题里非常常用。第二一定要写代码注释和模块说明。比赛最后一天总是手忙脚乱如果没有注释三天前写的代码自己都看不懂这真的很致命。我们每一段核心算法都会加一行注释说明输入输出最后整理代码附件时省了大量时间。第三不要迷信复杂的算法。我们的二等奖靠的不是模型有多“高级”而是每一个模型都紧扣题目、结果都能解释、图画得清楚。我们见过有人用神经网络做路径规划结果完全跑不动最后没时间写结果分析。能用经典方法解决的问题不要强行堆新模型。5. 后续扩展与我的个人体会这个题如果继续做深有几个方向非常有意思。一是把电机订购和路径学习做成联合优化而不是两个独立模块比如预算有限时优先买哪些机器人能显著降低学习难度二是把静态网络换成动态网络模拟血管堵塞或血流变化导致部分节点失效的情况三是用更真实的血管分叉几何信息做连续空间路径规划这意味着把图论模型升级成连续优化模型。我在实际处理这个题的过程中最大的一个心得是数学建模的核心不是写代码而是把生活问题翻译成数学问题的能力。血管机器人订购本质是资源分配问题所以用整数规划机器人找路本质是序贯决策问题所以用强化学习。这两步翻译做对了后面所有计算都是水到渠成。最后再分享一个我们队伍内部的小技巧每一个模型的代码跑通之后立刻截图保存结果。不要等全部做完再回头补截图因为比赛后期时间紧张时你可能根本没有机会重新完整地跑一遍程序。很多队伍最后论文里缺图、缺数据不是因为没做出来而是因为没有及时留存中间结果。这个习惯不仅让我们各种图表都齐全也让最后的论文撰写特别顺畅。本文还有配套的精品资源点击获取