如何用Python/PuLP构建库存不足时可行的运输线性规划模型
解决运输补货模型库存不足时的不可行问题
问题根源
你当前代码的核心问题是强制要求配送量等于门店需求(lpSum(...) == demand[s][i]),当总库存无法覆盖总需求时,模型必然无解。要实现“库存充足时100%满足需求,库存不足时耗尽库存并尽可能满足需求”,需要调整约束逻辑和目标函数。
修改方案
核心调整点:
- 放松需求约束:门店接收的商品量不能超过其需求,但无需强制等于需求;
- 调整目标函数:通过加权方式将“优先满足需求+最小化成本”的多目标转为单目标优化,确保先满足尽可能多的需求,再追求最低运输成本;
- 保留库存约束:仓库发出的商品量不能超过其库存(库存充足时可留余,库存不足时自动耗尽)。
修改后的完整代码
from pulp import * import pandas as pd # 仓库列表 warehouses = ["WHS_1","WHS_2","WHS_3"] # 仓库-商品库存字典 inventory = {"WHS_1": {"SKU_A":50,"SKU_B":100}, "WHS_2": {"SKU_A":50,"SKU_B":75} , "WHS_3": {"SKU_A":150,"SKU_B":25} , } # 门店列表 stores = ["Store1","Store2"] # 商品列表 items = ["SKU_A","SKU_B"] # 门店-商品需求字典 demand = { "Store1": {"SKU_A":100,"SKU_B":250}, "Store2": {"SKU_A":100,"SKU_B":50}, } # 仓库-门店-商品运输成本字典 costs = { "WHS_1": {"Store1": {"SKU_A":10.50,"SKU_B":3.75}, "Store2": {"SKU_A":15.01,"SKU_B":5.15}}, "WHS_2": {"Store1": {"SKU_A":9.69,"SKU_B":3.45}, "Store2": {"SKU_A":17.50,"SKU_B":6.06}}, "WHS_3": {"Store1": {"SKU_A":12.12,"SKU_B":5.15}, "Store2": {"SKU_A":16.16,"SKU_B":7.07}}, } # 创建问题实例,目标为最小化 prob = LpProblem("StoreAllocation", LpMinimize) # 生成所有可能的运输路线元组 routes = [(w, s, i) for w in warehouses for s in stores for i in items] # 创建运输量变量,非负整数 vars = LpVariable.dicts("Route", (warehouses, stores, items), 0, None, LpInteger) # 目标函数:优先满足需求(用大权重惩罚未满足的需求),再最小化运输成本 # 权重设为100(远高于最高运输成本7.07),确保优先满足需求 demand_satisfaction = lpSum([vars[w][s][i] for (w, s, i) in routes]) transport_cost = lpSum([vars[w][s][i] * costs[w][s][i] for (w, s, i) in routes]) prob += transport_cost - 100 * demand_satisfaction, "Minimize_Cost_Maximize_Demand" # 库存约束:仓库发出的商品量不能超过库存 for w in warehouses: for i in items: prob += ( lpSum([vars[w][s][i] for s in stores]) <= inventory[w][i], f"Inventory_Limit_{w}_{i}", ) # 需求约束:门店接收的商品量不能超过其需求 for s in stores: for i in items: prob += ( lpSum([vars[w][s][i] for w in warehouses]) <= demand[s][i], f"Demand_Limit_{s}_{i}", ) # 输出LP文件(可选) prob.writeLP("TestProblem.lp") # 求解模型 prob.solve() # 输出结果 print("Status:", LpStatus[prob.status]) # 只打印有运输量的路线(更清晰) for v in prob.variables(): if v.varValue > 0: print(v.name, "=", v.varValue) # 计算并打印实际满足的需求和真实运输成本 total_satisfied = sum(vars[w][s][i].varValue for w in warehouses for s in stores for i in items) print(f"Total Satisfied Demand = {total_satisfied}") # 还原真实成本:目标函数减去了加权项,需加回 print("Total Cost of Fulfillment = ", value(prob.objective) + 100 * total_satisfied)
关键修改说明
目标函数调整:
加入需求满足量的加权项,用-100 * demand_satisfaction实现“优先满足需求”的优先级——因为权重远高于运输成本,模型会先尽可能多的满足需求,再在这个基础上寻找最低成本的运输方案。最后输出时需要还原真实运输成本(加回加权项的影响)。约束调整:
- 库存约束保留
<=,允许库存充足时留余; - 需求约束从
==改为<=,避免因库存不足导致无解,同时保证不会给门店配送超过需求的商品。
- 库存约束保留
效果验证
- 当库存充足时,模型会100%满足所有需求,同时输出最低运输成本;
- 当库存不足时,模型会耗尽所有库存,尽可能满足需求,并输出该状态下的最低成本。
内容的提问来源于stack exchange,提问作者ctrlf_abalone
相关产品推荐
相关产品推荐

