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

基于PuLP实现列生成法求解一维下料问题的技术求助

用PuLP适配一维下料列生成问题的实操步骤

1. 定义核心参数

先把你的问题参数明确映射到代码变量:

  • 原始板材长度:L = 100
  • 成品规格与需求:
    • 规格列表:sizes = [45, 36, 31, 14]
    • 需求数量:demands = [9700, 61000, 39500, 21100]
  • 单根原始板材成本:cost_per_board = 100(对应初始目标505×100=50500美元)

2. 配置初始下料模式

替换成你实际的4种初始模式(示例为常见合理模式,可直接修改):

import pulp

# 初始下料模式:每行代表一种模式,元素对应各规格的下料数量(总长度≤100)
initial_patterns = [
    [2, 0, 0, 0],   # 2根45(总长度90)
    [0, 2, 0, 2],   # 2根36 + 2根14(总长度100)
    [0, 0, 3, 0],   # 3根31(总长度93)
    [0, 0, 0, 7]    # 7根14(总长度98)
]
n_patterns = len(initial_patterns)

3. 构建主问题(Master Problem)

主问题是线性规划,变量为各下料模式的使用量,约束满足需求,目标最小化总成本:

# 初始化主问题
master_problem = pulp.LpProblem("Cutting_Stock_Master", pulp.LpMinimize)

# 定义变量:每种模式的板材使用量(先放松为连续变量,迭代后转整数)
pattern_vars = pulp.LpVariable.dicts(
    "Pattern", 
    range(n_patterns), 
    lowBound=0, 
    cat='Continuous'
)

# 目标函数:总成本 = 模式使用量 × 单板材成本
master_problem += pulp.lpSum([pattern_vars[i] * cost_per_board for i in range(n_patterns)]), "Total_Cost"

# 需求约束:每种规格的下料总数≥需求
for j in range(len(sizes)):
    master_problem += pulp.lpSum([initial_patterns[i][j] * pattern_vars[i] for i in range(n_patterns)]) >= demands[j], f"Demand_Constraint_{sizes[j]}"

4. 构建子问题(Pricing Problem)

子问题是背包问题,用于寻找能降低总成本的新下料模式:

def solve_pricing_problem(dual_prices):
    # 初始化子问题(最大化减少成本)
    pricing_problem = pulp.LpProblem("Cutting_Stock_Pricing", pulp.LpMaximize)
    
    # 变量:新模式中各规格的下料数量(非负整数)
    x = pulp.LpVariable.dicts(
        "x", 
        range(len(sizes)), 
        lowBound=0, 
        cat='Integer'
    )
    
    # 目标函数:减少成本 = Σ(对偶价格[j]×下料数量[j]) - 1
    pricing_problem += pulp.lpSum([dual_prices[j] * x[j] for j in range(len(sizes))]) - 1, "Reduced_Cost"
    
    # 长度约束:下料总长度≤原始板材长度
    pricing_problem += pulp.lpSum([sizes[j] * x[j] for j in range(len(sizes))]) <= L, "Length_Constraint"
    
    # 求解子问题(关闭日志输出)
    pricing_problem.solve(pulp.PULP_CBC_CMD(msg=0))
    
    # 获取结果
    reduced_cost = pulp.value(pricing_problem.objective)
    new_pattern = [int(pulp.value(x[j])) for j in range(len(sizes))]
    
    return reduced_cost, new_pattern

5. 列生成循环迭代

循环求解主问题→获取对偶价格→求解子问题→添加新模式,直到无更优模式:

# 迭代循环
iteration = 0
while True:
    iteration += 1
    print(f"Iteration {iteration}")
    
    # 求解主问题
    master_problem.solve(pulp.PULP_CBC_CMD(msg=0))
    current_cost = pulp.value(master_problem.objective)
    print(f"当前总成本: {current_cost}")
    
    # 获取约束对偶价格
    dual_prices = [master_problem.constraints[f"Demand_Constraint_{sizes[j]}"].pi for j in range(len(sizes))]
    print(f"对偶价格: {dual_prices}")
    
    # 求解子问题
    reduced_cost, new_pattern = solve_pricing_problem(dual_prices)
    print(f"新模式减少成本: {reduced_cost}")
    print(f"新模式: {new_pattern}")
    
    # 终止条件:减少成本≤0(无更优模式)
    if reduced_cost <= 1e-6:
        break
    
    # 将新模式加入主问题
    pattern_vars[n_patterns] = pulp.LpVariable(f"Pattern_{n_patterns}", lowBound=0, cat='Continuous')
    master_problem += pattern_vars[n_patterns] * cost_per_board
    # 更新各需求约束
    for j in range(len(sizes)):
        master_problem.constraints[f"Demand_Constraint_{sizes[j]}"].addterm(pattern_vars[n_patterns], new_pattern[j])
    
    n_patterns += 1

# 迭代结束后,求解整数解
for var in pattern_vars.values():
    var.cat = 'Integer'

master_problem.solve(pulp.PULP_CBC_CMD(msg=0))
final_cost = pulp.value(master_problem.objective)
print(f"\n最终整数解总成本: {final_cost}")
print("模式使用情况:")
for i in range(n_patterns):
    if pulp.value(pattern_vars[i]) > 1e-6:
        pattern = initial_patterns[i] if i < len(initial_patterns) else new_pattern
        print(f"模式{i+1} ({pattern}): {int(pulp.value(pattern_vars[i]))} 根板材")

关键适配点

  • 初始模式替换:直接修改initial_patterns为你实际的4种下料模式,确保总长度≤100。
  • 对偶价格验证:迭代中输出的对偶价格会逐步收敛,可对比你提供的初始值(0.5,0.5,0.25,0.25)观察趋势。
  • 成本调整:若你的成本计算逻辑不同,直接修改cost_per_board参数即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 01:20:35