You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于PuLP的运输优化:如何融入运输量折扣机制

解决方案:在PuLP中实现运输量折扣的目标函数

要实现基于仓库总运输量的折扣规则,需要引入二进制变量标记是否满足折扣条件,通过约束将变量与运输量关联,最后构建包含折扣逻辑的线性目标函数。以下是具体实现步骤和完整代码:

1. 定义折扣标记变量

添加两个二进制变量,分别表示仓库B、C是否享受折扣:

# 二进制变量:1表示享受折扣,0表示不享受
disc_B = LpVariable("Discount_B", cat=LpBinary)
disc_C = LpVariable("Discount_C", cat=LpBinary)

2. 添加折扣触发约束

通过约束确保折扣仅在运输量达标时生效:

  • 仓库B总运输量≥200时,disc_B必须为1;否则为0
  • 仓库C总运输量≥600时,disc_C必须为1;否则为0
# 仓库B的折扣约束
total_ship_B = lpSum(vars["B"][j] for j in projects)
# 若disc_B=1,总运输量≥200;若disc_B=0,约束自动满足(左边≥0)
prob += total_ship_B >= 200 * disc_B, f"Disc_B_Min_Shipment"
# 若disc_B=0,总运输量≤199;若disc_B=1,约束上限为仓库B的供应量(600)
prob += total_ship_B <= 199 + (supply["B"] - 199) * disc_B, f"Disc_B_Max_Shipment"

# 仓库C的折扣约束
total_ship_C = lpSum(vars["C"][j] for j in projects)
prob += total_ship_C >= 600 * disc_C, f"Disc_C_Min_Shipment"
prob += total_ship_C <= 599 + (supply["C"] - 599) * disc_C, f"Disc_C_Max_Shipment"

3. 构建带折扣的目标函数

目标函数由基础总成本减去折扣金额组成,折扣仅在满足条件时生效:

# 计算无折扣的基础总成本
base_cost = lpSum([vars[w][j] * costs[w][j] for w in warehouses for j in projects])

# 仓库B的折扣金额:仅当disc_B=1时,减去5%的B路径总成本
discount_B = 0.05 * lpSum([vars["B"][j] * costs["B"][j] for j in projects]) * disc_B

# 仓库C的折扣金额:仅当disc_C=1时,减去10%的C路径总成本
discount_C = 0.1 * lpSum([vars["C"][j] * costs["C"][j] for j in projects]) * disc_C

# 最终目标函数:基础成本减去折扣金额
prob += base_cost - discount_B - discount_C, "Total_Transport_Cost"

4. 补充核心约束

原代码缺少供应和需求约束,必须添加以保证模型合理性:

# 供应约束:每个仓库的总发货量不超过其供应量
for w in warehouses:
    prob += lpSum(vars[w][j] for j in projects) <= supply[w], f"Supply_Limit_{w}"

# 需求约束:每个项目的总收货量等于其需求量
for j in projects:
    prob += lpSum(vars[w][j] for w in warehouses) == demand[j], f"Demand_Satisfaction_{j}"

完整修改后代码

# Creates a list of all the supply nodes
warehouses = ["A", "B", "C"]

# Creates a dictionary for the number of units of supply for each supply node
supply = {"A": 150, "B": 600, "C":1000}

# Creates a list of all demand nodes
projects = ["1", "2", "3"]

# Creates a dictionary for the number of units of demand for each demand node
demand = {
    "1": 150,
    "2": 450,
    "3": 900,
}

# Creates a list of costs of each transportation path
costs = [  # Projects
    [5,1,9],  # A   warehouses
    [4,2,8],  # B
    [8,7,2]   # C
]

# The cost data is made into a dictionary
costs = makeDict([warehouses, projects], costs, 0)

# Import PuLP modeler functions
from pulp import *

# Creates the 'prob' variable to contain the problem data
prob = LpProblem("Material Supply Problem", LpMinimize)

# Creates a list of tuples containing all the possible routes for transport
Routes = [(w, b) for w in warehouses for b in projects]

# A dictionary called 'Vars' is created to contain the referenced variables(the routes)
vars = LpVariable.dicts("Route", (warehouses, projects), 0, None, LpInteger)

# -------------------------- 新增折扣相关部分 --------------------------
# 二进制变量:标记是否享受折扣
disc_B = LpVariable("Discount_B", cat=LpBinary)
disc_C = LpVariable("Discount_C", cat=LpBinary)

# 仓库B的折扣触发约束
total_ship_B = lpSum(vars["B"][j] for j in projects)
prob += total_ship_B >= 200 * disc_B, f"Disc_B_Min_Shipment"
prob += total_ship_B <= 199 + (supply["B"] - 199) * disc_B, f"Disc_B_Max_Shipment"

# 仓库C的折扣触发约束
total_ship_C = lpSum(vars["C"][j] for j in projects)
prob += total_ship_C >= 600 * disc_C, f"Disc_C_Min_Shipment"
prob += total_ship_C <= 599 + (supply["C"] - 599) * disc_C, f"Disc_C_Max_Shipment"

# 构建带折扣的目标函数
base_cost = lpSum([vars[w][j] * costs[w][j] for w in warehouses for j in projects])
discount_B = 0.05 * lpSum([vars["B"][j] * costs["B"][j] for j in projects]) * disc_B
discount_C = 0.1 * lpSum([vars["C"][j] * costs["C"][j] for j in projects]) * disc_C
prob += base_cost - discount_B - discount_C, "Total_Transport_Cost"
# -------------------------- 折扣部分结束 --------------------------

# 补充供应与需求约束
for w in warehouses:
    prob += lpSum(vars[w][j] for j in projects) <= supply[w], f"Supply_Limit_{w}"

for j in projects:
    prob += lpSum(vars[w][j] for w in warehouses) == demand[j], f"Demand_Satisfaction_{j}"

# 求解模型
prob.solve()

# 打印结果
print("Status:", LpStatus[prob.status])
for v in prob.variables():
    if v.varValue > 0:
        print(f"{v.name}: {v.varValue}")
print(f"Total Cost: ${value(prob.objective):.2f}")

逻辑说明

  • 二进制变量disc_B和disc_C相当于"开关",只有当仓库总运输量满足阈值时才会被激活为1
  • 约束条件确保"开关"与运输量严格关联:不满足阈值时开关必须为0,满足时必须为1
  • 目标函数通过线性组合实现折扣计算,完全符合PuLP的线性规划要求(二进制变量与连续变量的乘积属于线性项)

内容的提问来源于stack exchange,提问作者Vasuki Rao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:15:20