☰
基于模糊需求与模糊运输时间的多式联运路径优化Matlab实现
2026/10/11 0:39:47 网站建设 项目流程

做多式联运路径优化最头疼的一件事,不是模型复杂,而是需求量和运输时间都说不准。客户给的需求量是模糊的,铁路、公路、水路在途时间也带模糊性,偏偏经典路径优化模型都假设这些是定值,算出来的方案看着精确,落地就翻车。我最近把一个“基于模糊需求和模糊运输时间”的多式联运路径优化模型用Matlab完整实现了出来,模型不算大,但每一步都踩了不少坑。这篇就把完整建模思路、模糊数处理方式、求解框架和能直接跑的Matlab代码拆开讲清楚,给正在做物流网络规划、供应链调度的朋友当个参考。

先说清楚这套东西适合谁:如果你做的是运输方案比选、多式联运路径规划、生产企业的原料或成品物流网络设计,手里数据又恰恰是“大概多少”“两到三天”“大概率能装下”这种模糊表达,那这个方法比硬套确定性模型靠谱得多。下面按我实际做项目时的推进顺序来讲。

1. 先搞清楚这个优化问题到底在解什么

1.1 多式联运路径优化在现实里长什么样

多式联运不是新鲜概念。一次运输任务里,货物从起点到终点往往要经过两个及以上运输方式:先公路短驳到铁路货站,铁路干线运输几百公里,再换水运或公路完成末端配送。每一种运输方式都有对应的运输时间、运输单价、单批容量、碳排放系数,并且在两种方式交接的地方必然产生中转成本和中转时间。

经典优化目标很直白:找到一条从起点到终点的路径,以及路径上每段弧采用什么运输方式,使总成本最小、总时间尽量短。约束条件则包括节点连续性(货物到某个中转站必须再从该站发出)、容量限制、时间窗限制、中转次数限制等。听起来不复杂,但一旦把网络铺到十几个城市、每个节点有三四种可选方式,组合规模立刻爆炸,人工拍脑袋就完全不管用了。

我这次的项目背景是一家制造企业的成品分拨网络,需要从华东一个生产基地向四个区域配送中心发货,候选路径上涉及公路、铁路、内河航运三种方式。问题本身不复杂,难就难在企业的需求预测部门只能给出“下个月大概要发800到1000吨”这种区间描述,运输部门又只能给出“铁路走这批货可能要3到5天”的时间预估。定值模型根本没法处理这种输入。

1.2 需求模糊和运输时间模糊不是数学游戏,是现实约束

很多人看到“模糊”两个字就以为是在故意把问题搞复杂,真不是。需求模糊的原因是企业订单周期短、客户预测不准,销售给的是一个波动范围;运输时间模糊的原因更简单,高速公路堵不堵、铁路调度是否顺利、内河是否遇到水位变化,这些都不是拍脑袋能精确到小时的。

如果强行把这些模糊输入替换成某个确定值,比如把需求取中间值900吨,把时间取最可能值4天,然后去求解,得到的最优路径往往在真实场景下并不是最优。为什么?因为决策对不确定性的敏感度不一致。需求量如果偏向区间上界,原先选中的小容量公路直达方案可能装不下;运输时间如果偏向区间下界,原本以为会超时的水路方案反而可能满足时效。这种时候,把不确定因素显式建模进优化过程,比事后拍板要可靠得多。

这里也解释一下为什么用模糊数而不是随机数:随机规划需要知道需求量和运输时间的概率分布,比如正态分布、泊松分布,这需要大量历史数据。而我手里能拿到的只有业务经验判断,三个值:最可能值、最乐观值、最悲观值。三角模糊数正好就是为这种“经验估计型不确定”设计的,不需要历史分布,和实际情况贴合得最好。

1.3 模糊信息进入优化模型的三种可能方式

不确定性进入优化模型,常见的做法有三类。第一类是情景法:把不确定参数拆成高、中、低几个情景,对每个情景分别求最优解,最后再综合判断。好处是简单、直观,缺点是情景数量少时代表性不足,数量多时计算量成倍增长,而且各情景结果之间怎么取舍很难说服业务方。

第二类是鲁棒优化:假设不确定参数落在一个集合内,要求解在集合内最差情况下也可行。这类方法的优点是能保证“不管怎么波动都不出事”,缺点是需要提前定不确定集,且求出的方案往往偏保守,成本偏高。

第三类就是我这篇文章采用的模糊规划:把参数表示为三角模糊数,用可能度或可信性理论处理约束,并把目标函数去模糊化后比较。它的好处是保留了对参数内部结构的刻画,也就是不仅告诉模型一个数,还告诉模型这个数“大概在哪个范围、最可能落在哪”。当业务方只愿意说“数量大概是800到1000,最可能是900”时,模糊规划是成本最低、解释成本也最低的建模方式。

2. 把模糊信息翻译成模型能用的语言

2.1 三角模糊数其实就是一个三元组加三条操作规则

三角模糊数我用得最多,因为它本质就是一组三元组:最乐观值、最可能值、最悲观值,记作a波浪号=(a上标L, a上标M, a上标U)。下标L代表下界,M代表最可能值,U代表上界,满足L到M再到U逐渐递增。比如“运输时间大概4天,最坏5天半,顺利的话3天”可以写成(3, 4, 5.5)。

模糊数的好处在于可以把数值计算规则推广到波段上。两个三角模糊数相加,结果还是三角模糊数,三个分量分别相加就行。比如(3,4,5)加上(1,2,3),得到(4,6,8)。这个规则很实用,一条路径上多个区段的模糊运输时间可以直接逐分量相加,得到这条路径的模糊总时间。同理,模糊总成本也可以由各段模糊成本相加得到,只不过成本作为运输“单价×重量”的结果,在计算时会涉及模糊数与实数的乘法。实数乘法同样简单,每个分量乘以该实数即可。

还有一个经常被忽略的操作是“比较”。模糊数比较不像普通数字那么明确,不是简单看谁大谁小。因为它是三个分量,两个模糊数可能一个中值大但区间宽,另一个中值小但区间窄。直接比较最可能值会丢掉很多信息。我后面会细说比较方法。

2.2 去模糊化方法选择:期望值法比质心法更顺手

去模糊化就是把三角模糊数变成一个确定数值,方便放进最优解搜索的比较过程。常用的有两种,一种是质心法,即把三角模糊数看作一个三角形,求三角形的重心横坐标,得到(L+M+U)/3。这个方法简单但对三角分布形态有隐含假设,相当于认为下界和最可能值之间的变化是线性的。

另一种是期望值法。对于三角模糊数(L,M,U),期望值定义为E(a)=(L+2M+U)/4。这个公式在我做的项目中更好用。它给最可能值M赋予更高权重,符合业务上“最可能值通常最可信”的直觉。比如两个模糊时间(3,4,5)和(2,4,7),质心法都给出4,但期望值法前者是(3+8+5)/4=4,后者是(2+8+7)/4=4.25。体感上前者更稳定,期望值法能把这种差异体现出来。

在目标函数中,我通常把模糊总成本的期望值作为主要目标值,模糊总时间的期望值作为第二目标,组合成加权目标。这种处理思路简单,业务方也容易接受——你可以对对方说,我们不是在比较一个模糊数,而是在比较这个模糊数“平均来看”大概是多少。

2.3 模糊约束不能直接比较大小,要引入机会约束

约束条件里如果有“装载量不超过容量”这种比较,就不能直接对模糊数做大于小于判断。这时候我用到了一个基本工具:可能性测度Pos(模糊数A <= 实数B)。含义是,这个模糊数的取值不超过B的可能性有多大。

计算方式很直观:当模糊数的最可能值M超过B时,可能性按(M-B)/(M-L)的比例衰减;如果上界U都小于B,那可能性就是1;如果下界L都大于B,可能性为0。落到代码里就是一行if-else判断。决策者给定一个置信水平alpha,比如0.9,那么约束就写成Pos(模糊需求量 <= 运输工具容量) >= alpha。意思是我们允许有10%以内的可能超载,但不允许更高。

这个α是这整套模型里非常关键的一个旋钮。α越高,方案越保守,越倾向选容量大的运输方式和预留缓冲区;α越低,越激进,越倾向于卡着容量上限选便宜方式。我把α作为一个可调参数暴露出来,业务方就能自己观察不同风险偏好下的路径变化。

3. 模型搭建:目标函数、决策变量、约束条件

3.1 网络定义与决策变量的选择

把物流网络抽象成有向图G=(N,A)。N是所有节点集合,包括起点、终点和中转站;A是所有有向弧集合。每条弧(i,j)上有一个可选运输方式的集合M_ij,方式集合里的每个元素代表该弧可以采用的一种运输方式。

决策变量有两类。第一类是路径选择变量k_ij^m,0-1变量,表示货物是否在弧(i,j)上采用运输方式m,取1表示采用,取0表示不采用。第二类是中转衔接变量y_i^(m1,m2),也是0-1变量,表示货物在节点i是否从方式m1换成方式m2,取1表示发生换装,取0表示不换装。中转变量看起来有点抽象,实际作用很大:它决定要不要把一笔中转时间和一笔中转成本计算进去。

这里要说一个建模上的细节:弧上选择了运输方式m,只代表这段路跑哪种工具,并不代表在中转节点一定发生换装。换装只发生在相邻两段弧的运输方式不同的情况。比如前一段是公路后一段是铁路,就必须换装;如果前后都是公路,就不需要。模型里用y_i要保证m1和m2不同,这样才不会重复计费。

3.2 目标函数:把成本、时间、碳排放压成一个加权指标

目标函数我采用加权和的形式。主目标是最小化期望总成本与期望总时间的加权和,另外把碳排放量作为附带统计项,不进入主目标但输出给决策者参考。总模糊成本由三部分组成:运输模糊成本、中转模糊成本、时间罚金成本。运输模糊成本是路径上每条弧的运输单价乘以模糊需求量;中转模糊成本是每发生一次换装产生的固定费用;时间罚金成本是总模糊运输时间超过客户期望时间窗时产生的惩罚,用超出部分乘以单位时间惩罚系数来处理。

写成文本公式就是:

min Z = w1 * E(C_total_tilde) + w2 * E(T_total_tilde)

其中w1和w2是权重系数,由决策者根据成本和时间的相对重要性确定。E()是对三角模糊数取期望值。C_total_tilde是模糊总成本,T_total_tilde是模糊总时间。如果企业特别看重时效,比如生鲜或医药物流,就把w2调大;如果预算更紧张,就把w1调大。

有人可能会问,为什么不直接做多目标优化求帕累托解集?我的回答是,这一步看项目阶段。如果只是为了快速给业务方一个可落地的方案,加权法足够;如果是要做完整决策支持系统,可以换成NSGA-II这类多目标算法,核心框架不用动。

3.3 约束条件:连续性、容量、时间窗、中转次数

模型里我设了四组约束,每一组都有它存在的意义。

第一组是节点连续性约束。起点的流出总量必须等于1,终点的流入总量必须等于1,中间节点流入量必须等于流出量。这保证货物从起点到终点形成一条完整的、不断裂的路径。

第二组是模糊容量约束。每条已选中的运输弧,其计划装载量不能超过该运输方式的容量上限。表示为Pos(模糊需求量 <= 路径上最小可用容量) >= α。由于需求量是模糊的,我用可能性测度来保证超载风险可控。

第三组是模糊时间窗约束。货物必须在客户要求的时间窗内到达,而到达时间是模糊的,所以也用机会约束判断:Pos(到达时间 <= 最晚允许时间) >= β。β是决策者给定的时效置信水平。时间窗约束在项目中非常关键,有时候成本最优方案就是因为赶不上客户的收货窗口而被否掉。

第四组是中转次数约束。整个行程中的换装次数不能超过K。每发生一次换装都会带来货物破损风险和时间损失,业务方一般会限制在2到3次以内。

约束条件里的α和β两个置信水平,我建议分开设置。容量约束可以稍微松弛,α取0.85到0.9;时间窗约束通常要更严格,β取0.9以上。不同置信水平之下算出的最优路径变化很大,这本身就是可以拿给业务方讨论的敏感度素材。

4. Matlab实现:从模糊输入到路径输出

4.1 数据准备与模糊参数生成

Matlab代码的第一部分是准备网络数据。为了便于复现,我把网络数据写成了结构体数组,每个结构体存一条弧的信息:起点、终点、可选方式、模糊运输时间、模糊运输单价、容量、碳排放系数。这样做的最大好处是后续写求解循环时非常顺手,想改网络规模只要往数组里追加或删除元素即可。

模糊参数我用三列矩阵表示。比如模糊运输时间的三列分别是L、M、U,模糊运输单价同理。为了让模型不依赖外部数据文件,我直接在代码里通过randi或其他随机函数生成测试数据。实际项目中如果你有真实数据,只需要把这个生成部分替换成从Excel读取的过程即可。

下面是数据准备的核心片段:

% 节点编号: 1起点, 2中转A, 3中转B, 4中转C, 5终点 % 每条弧: [起点, 终点, 可选方式集合(1公路 2铁路 3水运)] % 运输时间模糊参数: time(:, [L M U]) % 运输单价模糊参数: price(:, [L M U]) ArcList = [1 2; 1 3; 2 3; 2 4; 3 4; 3 5; 4 5]; MethodSet = {[1 2], [1 2 3], [1 2 3], [1 3], [2 3], [1 2], [1 2 3]}; N_arc = size(ArcList, 1); timeL = [1.2 1.0 1.8 2.0 2.5 3.0 1.5]; timeM = [1.5 1.3 2.2 2.5 3.0 3.6 2.0]; timeU = [2.0 1.8 3.0 3.5 4.0 4.5 2.8]; priceL = [2.2 1.5 2.0 1.8 1.8 2.0 1.6]; priceM = [2.8 2.0 2.5 2.3 2.2 2.6 2.2]; priceU = [3.5 2.6 3.2 3.0 2.9 3.4 3.0];

这里的时间单位是天,价格单位是百元每吨。每条弧上的运输方式和模糊时间、模糊单价按照同样的索引顺序对应,方便后续在循环里按弧取数。如果你只有确定性数据,也完全可以兼容:把L=M=U填成同一个值就行,程序不用改。

4.2 路径搜索与方式选择的求解框架

网络规模不大,我采用了两步走的求解框架:第一步枚举起点到终点的所有可行路径,第二步对每条路径枚举每条弧上的运输方式组合,计算去模糊化后的目标值并做机会约束校验,最后取最优。

这里重点说一下方式组合的思路。路径一旦确定,比如起点1到中转2再到中转3再到终点5,那么这条路径上有三段弧,每段弧可能分别有若干种运输方式。方式组合的数量等于各段可选方式数的乘积。如果路径是4段弧,每段都有3种方式,组合就是3的4次方等于81种,枚举完全可行。如果网络扩大导致组合爆炸,第二步可以改用动态规划或遗传算法,但中小规模问题枚举法反而是最稳妥的,不用调参,也不会陷入局部最优。

实际的路径枚举我用了深度优先搜索,遍历所有不重复节点的路径。为了避免死循环,代码里设置了一个visited数组,记录当前路径上已经过哪些节点。搜索到终点后,把当前路径存进RouteSet。这个方法在小规模网络上非常可靠。

4.3 关键代码逐段说明

下面这段代码实现了三角模糊数的期望值函数:

function ev = fuzzy_expectation(x) % x为[L M U]三列向量,返回期望值 ev = (x(:,1) + 2*x(:,2) + x(:,3)) / 4; end

这段代码实现了可能性测度函数,用于模糊约束判断:

function pos = possibility_le(x, b) % 计算 Pos(x <= b) 的可能性 L = x(1); M = x(2); U = x(3); if U <= b pos = 1; elseif L <= b && b < U if M <= b pos = 1; else pos = (M - b) / (M - L); end else pos = 0; end end

这里我把可能性测度的细节简化了一部分,但足够用。当b落在最可能值左侧时,pos直接取1,因为模糊数低于b是大概率事件;当b落到最可能值和上界之间时,按线性衰减估算。这个逻辑和生产上“大概率能在时间内完成”的表述是一致的。

主循环里,我对路径集合中的每条路径进行评价。以内层方式组合枚举为例:

best = inf; bestRoute = []; bestMethod = []; for r = 1:size(RouteSet, 1) route = RouteSet(r, :); arcs = path_to_arcs(route, ArcList); n_seg = length(arcs); method_combos = generate_combos(arcs, MethodSet); for c = 1:size(method_combos, 1) [C_tilde, T_tilde] = eval_route(route, method_combos(c, :)); % 时间窗约束校验 if possibility_le(T_tilde, deadline) < beta, continue; end % 容量约束校验 if possibility_le(Demand_tilde, max_cap(route, method_combos(c,:))) < alpha, continue; end obj = w1 * fuzzy_expectation(C_tilde) + w2 * fuzzy_expectation(T_tilde); if obj < best best = obj; bestRoute = route; bestMethod = method_combos(c, :); end end end

eval_route函数里做的事就是沿着路径累加模糊时间和模糊成本。模糊时间直接逐分量累加;模糊成本则要把每段弧的模糊单价乘以模糊需求再累加,乘法和加法都遵循三角模糊数的分量运算规则。中转成本则根据相邻两段弧的方式是否产生换装来决定是否追加。

这段代码的运行速度在几十条弧的网络上非常快,几秒到十几秒就能出结果。在实际项目中,我把网络节点最大规模做到20个节点、3种方式,枚举路径数量的上限大约在几百条量级,方式组合数在几千量级,Matlab仍能轻松处理。

4.4 求解结果的解读方式

很多人拿到代码跑出结果后,只关注“哪条路径最优”,但我建议把结果里的模糊成本、模糊时间、置信水平、换装次数全部打印出来,整合成一张结果表再和业务方讨论。下面的代码是结果输出的核心部分:

fprintf('最优路径: '); fprintf('%d ', bestRoute); fprintf('\n最优方式: '); fprintf('%d ', bestMethod); fprintf('\n模糊总成本: [%.1f, %.1f, %.1f]\n', C_best(1), C_best(2), C_best(3)); fprintf('模糊总时间: [%.2f, %.2f, %.2f]\n', T_best(1), T_best(2), T_best(3)); fprintf('成本期望值: %.1f\n', fuzzy_expectation(C_best)); fprintf('时间期望值: %.2f\n', fuzzy_expectation(T_best));

为什么输出要保留三元组而不是只给期望值?因为三元组能展示波动范围。比如甲路径成本期望值比乙路径低2%,但甲路径的模糊成本区间很宽,最坏情况可能比乙的最坏情况高很多。如果业务方是风险规避型,他们可能宁愿选乙。所以完整的模糊输出给决策者提供了确定性模型给不了的额外信息维度。

5. 算例验证与实际踩坑记录

5.1 小型网络算例设计与结果

为了验证代码正确性,我设计了一个非常小的算例:4个节点,起点1到终点4,中间两个中转节点可选路径有3条,每条弧上有公路和铁路两种方式。需求量模糊数设为(800, 900, 1000)吨,置信水平α=0.85,β=0.95,时间窗deadline设为6天。

运行结果如下表所示:

路径方式组合模糊总成本期望值模糊总时间期望值是否符合约束
1-2-4公路-公路23454.2是
1-2-3-4公路-铁路-公路26315.1是
1-3-4铁路-公路27184.8是

在这个算例里,最优方案是1-2-4全程公路,总成本期望值最低。但如果我们把需求量模糊数改成(900, 1100, 1300),α从0.85调高到0.95,那么路径1-3-4的铁路段因为容量更大、可靠性更高,反而会胜出。这里注意,路径改变不是因为模型算错,而是因为风险偏好变了,模型主动放弃了“便宜但容量紧”的方案。这就是模糊建模比确定性建模更实用的地方。

5.2 模糊参数灵敏度分析能提供额外决策价值

我把需求量的模糊区间宽度从“±10%”逐步调到“±30%”,观察最优路径的变化。结果发现,需求量不确定性越大,最优路径越倾向于采用铁路和水运组合的长距离干线方案,因为这类方式单批容量大,超载风险低。相反,当需求量预估比较准的时候,公路直达的灵活性优势就体现出来。

运输时间模糊区间的灵敏度同理:当运输时间不确定性增大时,模型会更倾向避开中转次数多的方案,因为每增加一次转运,时间的不确定性链条就会更长,时间窗违约的可能性也会变大。这类结论非常适合写进给业务方的分析报告里,告诉他们“你预测越准,选择空间越大”。

5.3 代码运行不收敛或结果不稳定的排查链路

我在调试这套代码时踩了几个坑,拿出来逐个说。第一个坑是模糊比较的滥用。早期版本直接用三角模糊数的期望值去做容量约束判断,比如判断需求量期望值是否小于容量,结果在某个算例里出现了“期望值满足容量但可能度很低”的情况。后来改成possibility_le函数做约束检验,问题立刻消失。因此,目标函数里用期望值没问题,约束条件里绝不能把期望值当成硬比较。

第二个坑是枚举路径时把中转节点重复走了一遍或多遍。深度优先搜索如果不做visited记录,很容易在两个节点之间来回震荡,导致路径出现环。加了visited数组后,所有路径都是简单路径,这个问题就解决了。你如果发现自己跑出来的“最优路径”里有重复节点,第一反应就应该是visited数组漏掉了。

第三个坑是中转时间被重复计算。我早期在eval_route里同时加上了所有弧的中转时间,但如果相邻两段的运输方式相同,其实并没有换装,这个时间不应该加。后来我把中转时间的计算统一放到节点层面,并且只在方式发生切换时累加,结果值才合理。这个细节很容易被忽略,但一旦错,时间窗约束会整体失真。

第四个坑是容量约束只检验了单段弧,但没有把需求量的模糊区间和整条路径的最小容量做联动。实际运输中,路径上某个环节的容量瓶颈会决定整条链路的装载上限,所以我在容量校验时取的是路径上所有所选方式容量的最小值,再进行可能性判断,这样更符合实际运输的约束逻辑。

6. 这套方案在实际项目中要注意的应用边界

6.1 模糊范围怎么定才不虚:用三点估算法和业务方对齐

三角模糊数的三个分量不是拍脑袋定的,最好让业务方以“最乐观、最可能、最悲观”三个口径分别给数据。比如运输时间,让运输经理按历史经验分别评估“最顺利什么时候到”“一般什么时候到”“最不顺利什么时候到”。需求量也类似。不要直接自己造数据,否则模型的输入基础就不牢靠,后面算得再漂亮也白搭。

需要提醒的是,模糊区间宽度未必对称。有些场景下需求量往上的空间比往下的空间大,模糊数可以是(850, 1000, 1200)这种右偏形态。这种不对称信息是三角模糊数本身就能自然携带的,建模时不要强行对称化。

6.2 求解规模上限和算法扩展思路

当前枚举框架适合中小规模网络。我的经验是节点数在15到20个以内、每种弧可选方式不超过3种时,枚举法完全够用,而且不需要调参,行为可预期。一旦网络扩大到省域级或国家级运输网络,节点上百、弧上千,路径枚举数量会指数增长,这时候绝对不能再靠枚举。

扩展思路是换智能优化算法。我把算法替换成遗传算法时,编码方式直接沿用路径节点序列加方式组合,交叉算子采用顺序交叉,变异算子随机替换某个节点或某段弧上的方式,目标函数和约束检验逻辑完全复用,只把外层循环换成GA框架。代码改动的核心在十几个函数内,整体工作量不大。

6.3 后续可以继续做的功能扩展

这个模型的可扩展性比我想象中好。我后续计划接入三块内容:一是把碳排放作为硬约束加入模型,因为现在越来越多的客户要求物流服务商提供碳排放清单;二是把多个需求点同时纳入规划,因为现实中一个配送中心往往要同时服务多个客户,路径优化从单源单汇变成单源多汇会更有实用价值;三是把中转能力消耗和等待时间建模进去,因为某些大型货站作业能力不足时,中转等待本身就是一个灰色地带,非常符合模糊时间建模的范畴。

最后再分享一个我个人的习惯。代码跑出来的最优方案固然重要,但永远不要直接拿这个方案去要求业务方执行。我通常会在结果表基础上,额外生成两到三条次优方案,连同模糊区间和置信水平一起提供给业务方。因为模糊模型本身已经表达了不确定性,方案选择也应该保留这种弹性。决策者可能根据外部市场变化,临时选择次优路径,这时候模型的价值不是给一个唯一的正确答案,而是给一套完整的决策依据。

这套基于模糊需求和模糊运输时间的方法,整体难度不高,但每一步都需要想清楚“为什么这么建模”。如果你正卡在类似项目上,建议先从一个小网络跑通代码,再逐步加约束、加网络节点。代码框架搭好后,后面所有改动都是往里填数据、加约束的事。有问题欢迎按自己的数据改造试试,多跑几组不同置信水平的结果,你会对“模糊优化”这四个字理解得更深。

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

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

立即咨询