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

Scipy Optimize Minimize组合优化:仅整数解设置及方案合理性咨询

问题分析与解决方案

为什么你当前的代码得不到正确的0-1解?

  • scipy.optimize.minimize(包括你用的SLSQP方法)是连续优化求解器,只能处理实数变量。哪怕你设置了(0,1)的边界,它会输出0到1之间的实数,而非严格的0或1整数。你得到的[0,0,0,0,0]只是连续空间下的局部最优,不是你要的整数规划解。
  • 目标函数里的max()是不可微函数,SLSQP依赖梯度信息计算最优方向,这种非光滑函数会导致求解器无法正确计算梯度,进而给出错误结果。

如何设置0-1整数约束?

你需要用整数规划(IP)求解器,而非连续优化工具。以下是两种可行方案:

方案一:用PuLP实现(解决你说的动态排放费问题)

PuLP完全支持总量计算的排放费,你之前的问题是没掌握线性化max()函数的方法——可以用辅助变量把非光滑的排放费转化为线性约束。

示例代码:

from pulp import LpProblem, LpVariable, LpMinimize, lpSum, value

# 工厂列表与数据
factories = ['1', '2', '3', '4', '5']
data = {
    '1': 1.2,
    '2': 1.0,
    '3': 1.7,
    '4': 1.8,
    '5': 1.6
}

# 参数预处理(提前把31乘进去)
unit_cost_b = 8
limit_b = 100
echarge_b = 0.004 * 31

unit_cost_a = 5
limit_a = 60
echarge_a = 0.007 * 31

# 创建最小化问题
prob = LpProblem("Factory_Product_Assignment", LpMinimize)

# 定义0-1变量:x[f] = 1表示工厂f生产产品b,0表示生产a
x = LpVariable.dicts("Assign", factories, cat='Binary')

# 计算生产a/b的总用量与工厂数量(线性表达式)
total_usage_a = lpSum(data[f] * (1 - x[f]) for f in factories)
count_a = lpSum(1 - x[f] for f in factories)
total_usage_b = lpSum(data[f] * x[f] for f in factories)
count_b = lpSum(x[f] for f in factories)

# 用辅助变量线性化max(超额排放, 0)
# 处理产品a的超额排放
emission_excess_a = LpVariable("Emission_Excess_A", lowBound=0)
prob += emission_excess_a >= total_usage_a - count_a * limit_a
prob += emission_excess_a >= 0

# 处理产品b的超额排放
emission_excess_b = LpVariable("Emission_Excess_B", lowBound=0)
prob += emission_excess_b >= total_usage_b - count_b * limit_b
prob += emission_excess_b >= 0

# 构建目标函数:单位成本 + 排放费
total_unit_cost = lpSum(unit_cost_a * (1 - x[f]) + unit_cost_b * x[f] for f in factories)
total_emission_cost = emission_excess_a * echarge_a + emission_excess_b * echarge_b
prob += total_unit_cost + total_emission_cost

# 注意:你原代码里的约束sum(x)=5意味着所有工厂都生产b,这可能不符合需求,根据实际情况调整
# prob += lpSum(x[f] for f in factories) == 5

# 求解
prob.solve()

# 输出结果
print("最优分配结果:")
for factory in factories:
    print(f"工厂{factory}: {'产品b' if value(x[factory]) == 1 else '产品a'}")
print("总成本:", round(value(prob.objective), 2))

方案二:使用OR-Tools的CP-SAT求解器

OR-Tools是谷歌的开源优化工具,对0-1整数规划支持极佳,处理非光滑成本也很方便:

from ortools.linear_solver import pywraplp

# 创建求解器
solver = pywraplp.Solver.CreateSolver('SCIP')
if not solver:
    exit()

# 工厂与数据
factories = ['1', '2', '3', '4', '5']
data = {'1': 1.2, '2': 1.0, '3': 1.7, '4': 1.8, '5': 1.6}

# 参数预处理
unit_cost_b = 8
limit_b = 100
echarge_b = 0.004 * 31
unit_cost_a = 5
limit_a = 60
echarge_a = 0.007 * 31

# 定义0-1变量
x = {f: solver.IntVar(0, 1, f"x_{f}") for f in factories}

# 计算总用量与工厂数
total_usage_a = solver.Sum(data[f] * (1 - x[f]) for f in factories)
count_a = solver.Sum(1 - x[f] for f in factories)
total_usage_b = solver.Sum(data[f] * x[f] for f in factories)
count_b = solver.Sum(x[f] for f in factories)

# 辅助变量处理超额排放
emission_excess_a = solver.NumVar(0, solver.infinity(), "excess_a")
solver.Add(emission_excess_a >= total_usage_a - count_a * limit_a)
solver.Add(emission_excess_a >= 0)

emission_excess_b = solver.NumVar(0, solver.infinity(), "excess_b")
solver.Add(emission_excess_b >= total_usage_b - count_b * limit_b)
solver.Add(emission_excess_b >= 0)

# 目标函数:总成本最小化
total_cost = solver.Sum(unit_cost_a * (1 - x[f]) + unit_cost_b * x[f] for f in factories)
total_cost += emission_excess_a * echarge_a + emission_excess_b * echarge_b
solver.Minimize(total_cost)

# 求解并输出结果
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
    print("最优分配结果:")
    for f in factories:
        print(f"工厂{f}: {'产品b' if x[f].solution_value() == 1 else '产品a'}")
    print("总成本:", round(solver.Objective().Value(), 2))
else:
    print("未找到最优解")

关于你当前方法的正确性

你用scipy连续优化的方法不正确,核心原因有两个:

  1. 无法处理整数约束,得到的解不是严格的0或1;
  2. 目标函数中的max()是非光滑函数,SLSQP这类依赖梯度的求解器无法正确处理,容易陷入局部最优或返回错误结果。

另外注意:你原代码里的约束np.sum(x)-5=0要求所有工厂都生产产品b(因为x[i]=1代表生产b),这可能和你的初始预期矛盾,建议根据实际需求调整这个约束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 14:37:05