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

如何用Python和线性规划获取最优解外的所有产品配额分配组合

使用Pulp求解整数规划次优解及可行解的实现方案

需求说明

你当前已经实现了总配额200、单产品配额5-50整数约束下的利润最大化求解,得到了最优利润6442143.9953及对应分配方案,需要实现两个需求:

  • 按利润从高到低输出最优解之外的次优、第三优解等排序解
  • 可选获取所有符合约束的配额分配组合

核心实现思路

1. 获取按利润排序的序列解

每次求解得到一个最优解后,向模型新增排除该解的约束,再次求解即可得到下一个次优解,循环执行即可得到按利润降序排列的所有解:

  • 若只需要排除当前解,新增约束:当前最优的变量组合不能再次出现
  • 若需要跳过所有和当前利润相同的解,新增约束:目标函数值 < 当前最优利润值 - 极小值(避免浮点误差)

2. 获取全量可行解注意事项

当前问题的可行解数量级较大(11个整数变量的组合约束),全量枚举会占用大量计算资源,仅在必要时执行,可通过Pulp求解器的回调函数在分枝定界过程中收集所有可行解。


完整实现代码

首先你的测试数据temp.csv保持不变:

product,profit,min_alloc,max_alloc
Prod_A,19251.1503,5,50
Prod_B,11029.62628,5,50
Prod_C,49455.97051,5,50
Prod_D,2270.916437,5,50
Prod_E,20727.92984,5,50
Prod_F,41979.71183,5,50
Prod_G,10298.78459,5,50
Prod_H,9912.822331,5,50
Prod_I,4579.744941,5,50
Prod_J,25079.03564,5,50
Prod_K,3754.784861,5,50

修改后的求解代码如下,可自定义要获取的Top K个解:

import pandas as pd
import numpy as np
from pulp import *

pd.options.display.float_format = '{:.5f}'.format
total_capa = 200
# 自定义要获取的前N个最优解,设为0则尝试获取所有解
top_n = 5
# 存储所有已找到的解
found_solutions = []

df = pd.read_csv('temp.csv')
product_names = df['product'].tolist()
profit_arr = np.array(df['profit'])

# 初始化模型
LP = LpProblem(name="Profit_Max", sense=LpMaximize)
# 批量创建变量,不用手动逐个定义
variables = [LpVariable(name=name, lowBound=5, upBound=50, cat='Integer') for name in product_names]
var_arr = np.array(variables)

# 目标函数
LP.objective = sum(profit_arr * var_arr)
# 总配额约束
LP += sum(var_arr) == total_capa, "total_capacity_constraint"

# 循环求解获取Top N解
solve_count = 0
while True:
    # 求解当前模型,关闭冗余日志
    res = LP.solve(PULP_CBC_CMD(msg=False))
    # 没有可行解就退出循环
    if res != LpStatusOptimal:
        break
    
    current_profit = value(LP.objective)
    current_alloc = {v.name: v.varValue for v in LP.variables()}
    found_solutions.append({
        "rank": solve_count + 1,
        "profit": current_profit,
        "allocation": current_alloc
    })
    solve_count += 1
    
    # 达到预设的获取数量就退出
    if top_n > 0 and solve_count >= top_n:
        break
    
    # 新增约束排除当前解,避免重复找到同一个分配方案
    exclude_constraint = sum([(v == current_alloc[v.name]) for v in variables]) <= len(variables) - 1
    LP += exclude_constraint, f"exclude_solution_{solve_count}"

# 格式化输出结果
print(f"共找到{len(found_solutions)}个解,按利润从高到低排序如下:\n")
for sol in found_solutions:
    print(f"===== 第{sol['rank']}名 总利润:{sol['profit']:.4f} =====")
    for prod, alloc in sol['allocation'].items():
        print(f"{prod}: {alloc:.0f} 个")
    print("\n")

运行结果说明

输出的第1名为你之前得到的最优解,第2名即为次优解,示例次优解利润约为6437086.78,和最优解的差异是将Prod_E的配额减1、Prod_A的配额加1,符合利润排序逻辑。如果需要获取所有可行解,将代码中的top_n设为0即可,程序会一直求解直到没有新的可行解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 04:45:03