在和中,我们探讨了求解器如何在复杂解空间中高效搜索“最优解”。
然而,优化问题的核心是将业务需求转化为数学模型。
本文聚焦目标函数的设计,通过上海到贵州的咖啡豆配送案例,展示不同目标函数(最短路径、最低碳排放、多目标优化)如何驱动路径选择,并结合可视化结果阐释其业务意义。
一、从业务到建模:五步法解析
优化问题的第一步是将业务语言转化为模型语言,以下是路径优化的五步建模法:
步骤
示例(路径优化)
明确优化目标(目标函数)
最小化总距离、总碳排放或综合成本
识别变量(决策变量)
每段路径是否选择(0/1)
写出限制条件(约束)
所有客户必须服务、路径经过指定节点(如C)
构造数学模型(MIP形式)
用线性等式/不等式表达目标与约束
调用求解器求解
使用 NetworkX、OR-Tools 或 Gurobi 获取解
目标函数定义了“最优解”的含义,直接映射企业战略优先级。本文通过配送案例,分析单一目标(最短路径、最低碳排放)和多目标优化的路径选择及其业务影响。
二、案例设定:上海到贵州的咖啡豆配送
在上一篇文章我们讲解了碳排放的计算方法,这次我们模拟更真实的场景,用业务语言结合碳排放的场景讲解运筹优化中不同的优化目标是怎样影响决策结果的,结果是最后行为的反应,是价值观的呈现。
2.1 业务场景
你是一家高端咖啡连锁的物流经理,需从上海配送中心(DC)将2吨咖啡豆运至贵阳门店(E),并在遵义(C)卸下1吨支持区域仓库,总时限30小时,以支持新品发布会。运输网络包括节点:A(武汉)、B(长沙)、C(遵义,强制中转)、D(重庆)、F(成都)、G(昆明)。
2.2 运输方式与碳排放
根据EU EN 16258标准,运输方式参数如下:
公路:碳排放因子 0.096 kg CO₂e/吨·km,运费 4.0 元/km(C→E 为 2.5 元/km),中等速度,无转运成本。
铁路:碳排放因子 0.028 kg CO₂e/吨·km,运费 1.0 元/km,速度慢,转运成本 100 元/节点,转运延时 2 小时/节点。
航空:碳排放因子 2.1 kg CO₂e/吨·km,运费 7.0 元/km,速度快,转运成本 200 元/节点,转运延时 1 小时/节点。
约束:
运输能力:满足 2 吨需求(C 前 2 吨,C 后 1 吨)。
时限:总时间 ≤ 30 小时。
强制中转:路径必须经过 C。
转运成本:铁路 100 元/节点,航空 200 元/节点。
时间惩罚:350 元/小时(反映紧急性)。
目标:
最小化总距离(经过 C)。
最小化总碳排放(经过 C)。
平衡距离、碳排放、时间和转运成本(经过 C,C→E 优先航空)。
路径
距离(km)
运输方式
货重(吨)
碳排放因子(kg CO₂e/吨·km)
运费(元/km)
时间(h)
转运成本(元)
DC→A
700
公路
2
4.0
13.0
0
DC→B
600
公路
2
4.0
12.0
0
DC→D
1000
铁路
2
1.0
24.0
100
B→C
500
公路
2
4.0
10.0
0
D→C
400
铁路
2
1.0
10.0
100
C→E
250
航空
1
2.1
7.0
1.5
200
C→E
350
公路
1
2.5
9.0
0
C→E
350
铁路
1
1.0
9.0
100
三、单一目标优化:最短路径 vs 最低碳排放
我们首先分析两种单一目标的结果,揭示目标函数如何影响路径选择。
3.1 构建配送网络
import networkx as nx import matplotlib.pyplot as plt # 设置中文字体 plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Noto Sans CJK SC'] plt.rcParams['axes.unicode_minus'] = False # 创建多重图 G = nx.MultiDiGraph() # 边数据(基于 EU EN 16258 标准) edges = [ ('DC', 'A', {'distance': 700, 'weight': 2, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 13.0, 'trans_cost': 0}), ('DC', 'B', {'distance': 600, 'weight': 2, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 12.0, 'trans_cost': 0}), ('DC', 'D', {'distance': 1000, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 24.0, 'trans_cost': 100}), ('DC', 'F', {'distance': 950, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 23.0, 'trans_cost': 100}), ('DC', 'G', {'distance': 1100, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 27.0, 'trans_cost': 100}), ('A', 'C', {'distance': 650, 'weight': 2, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 13.0, 'trans_cost': 0}), ('B', 'C', {'distance': 500, 'weight': 2, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 10.0, 'trans_cost': 0}), ('D', 'C', {'distance': 400, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 10.0, 'trans_cost': 100}), ('F', 'C', {'distance': 600, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 15.0, 'trans_cost': 100}), ('G', 'C', {'distance': 700, 'weight': 2, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 17.0, 'trans_cost': 100}), ('C', 'E', {'distance': 250, 'weight': 1, 'carbon_factor': 2.1, 'mode': '航空', 'cost_per_km': 7.0, 'time': 1.5, 'trans_cost': 200}), ('C', 'E', {'distance': 350, 'weight': 1, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 2.5, 'time': 9.0, 'trans_cost': 0}), ('C', 'E', {'distance': 350, 'weight': 1, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 9.0, 'trans_cost': 100}), ('A', 'E', {'distance': 900, 'weight': 1, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 18.0, 'trans_cost': 0}), ('B', 'E', {'distance': 700, 'weight': 1, 'carbon_factor': 0.096, 'mode': '公路', 'cost_per_km': 4.0, 'time': 14.0, 'trans_cost': 0}), ('D', 'E', {'distance': 450, 'weight': 1, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 11.0, 'trans_cost': 100}), ('F', 'E', {'distance': 700, 'weight': 1, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 17.0, 'trans_cost': 100}), ('G', 'E', {'distance': 600, 'weight': 1, 'carbon_factor': 0.028, 'mode': '铁路', 'cost_per_km': 1.0, 'time': 15.0, 'trans_cost': 100}), ] # 加入图中 for u, v, attr in edges: attr['carbon'] = attr['distance'] * attr['weight'] * attr['carbon_factor'] attr['cost'] = attr['distance'] * attr['cost_per_km'] G.add_edge(u, v, **attr) # 确保路径经过 C def get_valid_paths(G, source, target, mandatory_node): valid_paths = [] for path in nx.all_simple_paths(G, source, target, cutoff=10): if mandatory_node in path: valid_paths.append(path) return valid_paths # 获取所有经过 C 的路径 all_paths = get_valid_paths(G, 'DC', 'E', 'C')
3.2 最短路径:最小化总距离
def get_path_metrics(G, path): total_distance = 0 total_carbon = 0 total_cost = 0 total_time = 0 for u, v in zip(path, path[1:]): for k in G[u][v]: if G.edges[u, v, k]['mode'] == '公路': total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] break else: k = list(G[u][v].keys())[0] total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] return total_distance, total_carbon, total_cost, total_time shortest_path = min(all_paths, key=lambda p: get_path_metrics(G, p)[0]) shortest_distance, shortest_carbon, shortest_cost, shortest_time = get_path_metrics(G, shortest_path)结果:
路径: DC(上海) → B(长沙) → C(遵义) → E(贵阳)
总距离: 1450 km
总碳排放: 244.80 kg CO₂e
总运费: 4850.00 元
总时间: 31.00 小时
业务解读:
优势: 选择最短路径(DC→B:600 km,B→C:500 km,C→E:350 km,公路),总距离最短,适合追求物流效率的场景。
代价: 碳排放较高(244.80 kg CO₂e,因公路 0.096 kg CO₂e/吨·km),时间略超 30 小时(31 小时),需评估是否接受。
适用场景: 成本敏感、时间要求适中的常规配送。
def get_carbon_path_metrics(G, path): total_distance = 0 total_carbon = 0 total_cost = 0 total_time = 0 for u, v in zip(path, path[1:]): for k in G[u][v]: if G.edges[u, v, k]['mode'] == '铁路': total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] break else: k = list(G[u][v].keys())[0] total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] return total_distance, total_carbon, total_cost, total_time carbon_path = min(all_paths, key=lambda p: get_carbon_path_metrics(G, p)[1]) carbon_distance, carbon_total, carbon_cost, carbon_time = get_carbon_path_metrics(G, carbon_path)结果:
路径: DC(上海) → D(重庆) → C(遵义) → E(贵阳)
总距离: 1750 km
总碳排放: 75.60 kg CO₂e
总运费: 2050.00 元
总时间: 43.00 小时
业务解读:
优势: 选择铁路(DC→D:1000 km,D→C:400 km,C→E:350 km),碳排放最低(75.60 kg CO₂e),运费低(2050 元),符合 ESG 目标。
代价: 距离较长(1750 km),时间超长(43 小时),不适合紧急配送。
适用场景: 环保优先、时间宽松、预算有限的场景。
在咖啡豆配送案例中,单一目标优化暴露了局限性:
最短路径(DC→B→C→E)距离最短(1450 km),但时间略超 30 小时(31 小时),不满足新品发布会的紧急需求,且碳排放较高(244.80 kg CO₂e)。
最低碳排放路径(DC→D→C→E)环保(75.60 kg CO₂e)且成本低(2050 元),但时间过长(43 小时),无法满足 30 小时时限。
业务现实:企业需同时考虑成本控制(运费、转运成本)、环保合规(ESG 目标,碳税压力)、时间效率(新品发布会客户履约)。单一目标优化会导致其他关键指标恶化,如仅追求低碳排放会牺牲时间,影响客户体验。
因此,需要多目标优化,在距离、碳排放、时间和成本间找到平衡,满足紧急配送需求(时间 ≤ 30 小时),同时兼顾成本和环保。
4.2 解决方案:加权目标函数法
我们选择加权目标函数法,将多目标合并为单一目标函数: 距 离 碳 排 放 时 间 转 运 成 本
为何选择加权法?
场景驱动:新品发布会要求时间优先(≤ 30 小时),航空(C→E,1.5 小时)是关键选择;同时,需平衡成本(公路、铁路运费更低)和碳排放(ESG 要求)。
简洁高效:将多目标转化为单目标,适合实时物流系统,减少人工干预。
灵活性:通过调整权重(如放大时间惩罚),可适配不同业务场景。
备选方法:帕累托前沿法可生成多组折中解,但需人工选择,计算复杂,不适合实时决策。本案例优先自动化,故选择加权法。
4.3 权重设定与业务依据
权重反映业务优先级,基于以下逻辑:
距离 元 :每公里约 1 元运营成本(油费、维护等)。
碳 排 放 元 ₂ :碳税约 0.5 元/kg CO₂e,ESG 目标放大权重至 2.0,强调环保。
时 间 元 小 时 :紧急配送延误成本高,350 元/小时反映客户履约压力。
转 运 成 本 元 元 :铁路(100 元/节点)、航空(200 元/节点)直接计入。
实现细节:
优先 C→E 航空(1.5 小时,满足时限)。
选择 DC→A(武汉)以平衡距离和成本,相比 DC→D(铁路)时间更短。
# 加权成本 for u, v, k in G.edges(keys=True): edge = G.edges[u, v, k] edge['weighted_cost'] = edge['distance'] * 1.0 + edge['carbon'] * 2.0 + edge['time'] * 350.0 + edge['trans_cost'] * 1.0 # 加权路径,优先 C→E 航空且选择 DC→A def get_weighted_path(G, source, target, mandatory_node): valid_paths = get_valid_paths(G, source, target, mandatory_node) ifnot valid_paths: print("错误:未找到经过 C 的路径!") returnNone min_cost = float('inf') best_path = None for path in valid_paths: if path[-2:] == ['C', 'E'] and path[1] == 'A': for k in G['C']['E']: if G.edges['C', 'E', k]['mode'] == '航空': cost = sum(G.edges[u, v, list(G[u][v].keys())[0]]['weighted_cost'] for u, v in zip(path[:-1], path[1:-1])) + G.edges['C', 'E', k]['weighted_cost'] if cost < min_cost: min_cost = cost best_path = path if best_path isNone: print("警告:未找到经过 A 且 C→E 为航空的路径,切换到最小加权成本路径") for path in valid_paths: cost = sum(G.edges[u, v, list(G[u][v].keys())[0]]['weighted_cost'] for u, v in zip(path, path[1:])) if cost < min_cost: min_cost = cost best_path = path if best_path isNone: print("错误:未找到有效加权路径!") returnNone return best_path weighted_path = get_weighted_path(G, 'DC', 'E', 'C') if weighted_path isNone: print("程序终止:加权路径为空") exit() # 计算加权路径指标 def get_weighted_path_metrics(G, path): total_distance = 0 total_carbon = 0 total_cost = 0 total_time = 0 for u, v in zip(path, path[1:]): if u == 'C'and v == 'E': for k in G[u][v]: if G.edges[u, v, k]['mode'] == '航空': total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] break else: for k in G[u][v]: if G.edges[u, v, k]['mode'] == '公路': total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] break else: k = list(G[u][v].keys())[0] total_distance += G.edges[u, v, k]['distance'] total_carbon += G.edges[u, v, k]['carbon'] total_cost += G.edges[u, v, k]['cost'] + G.edges[u, v, k]['trans_cost'] total_time += G.edges[u, v, k]['time'] return total_distance, total_carbon, total_cost, total_time weighted_distance, weighted_carbon, weighted_cost, weighted_time = get_weighted_path_metrics(G, weighted_path)结果:
路径: DC(上海) → A(武汉) → C(遵义) → E(贵阳)
总距离: 1600 km
总碳排放: 784.20 kg CO₂e
总运费: 7350.00 元
总时间: 27.50 小时
业务解读:
优势: 选择 DC→A→C(公路),C→E(航空),时间最短(27.50 小时),满足 30 小时时限,适合紧急配送。
代价: 碳排放高(784.20 kg CO₂e,因航空 2.1 kg CO₂e/吨·km),运费高(7350 元)。
适用场景: 时间敏感的场景(如新品发布会),需接受高成本和碳排放。
五、尾声:模型是业务价值的映射
核心逻辑:
目标函数不同 → 最优解不同 → 决策路径自然变化
不同目标函数输出不同路径,反映了背后的业务权衡:
目标函数
优先级
路径表现
最短路径
成本敏感
距离最短但略超时限
最低碳排
ESG 优先
超时严重但碳足迹极低
加权优化
综合平衡
满足时间但成本高、排放高
它不仅仅是数学形式的改变,更是对企业战略诉求的映射。
具体的建模落地实践感悟参考
建模不是在“找一条最好的路”,而是在“表达你在业务中最看重什么”。而模型,只是忠实地执行你的表达。
近期活动
点击图片·查看详情
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.