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

基于OR-Tools求解食材最优等比缩放系数满足营养区间约束

解决方案

核心调整逻辑

  • 原有代码变量定义错误,不需要为每个营养素单独定义变量,唯一决策变量是所有食材共用的缩放系数k
  • 先计算无缩放状态下各营养素的基准总含量,再乘以k后约束在对应营养素的上下限范围内
  • 最优解目标为总营养尽可能接近各营养素上下限的中位数,我们将目标设定为最小化各营养素实际值与中位数的相对偏差和,对绝对值偏差做线性化处理适配线性规划要求

修改后完整可运行代码

from ortools.linear_solver import pywraplp

# 计算无缩放时所有食材的基准总营养
def get_base_nutrient_sum(ingredients):
    base = [0.0 for _ in range(4)]
    for ingredient in ingredients:
        amount = ingredient[1]
        per_g_nutrients = ingredient[2]
        for i in range(4):
            base[i] += amount * per_g_nutrients[i]
    return base

def main():
    nutrients = [
        ['卡路里', 557.7, 669.24],
        ['脂肪', 39.04, 51.43],
        ['碳水', 0, 13],
        ['蛋白质', 31.19, 41.59]
    ]

    # 名称, 用量(克), [每克卡路里、脂肪、净碳水、蛋白质含量]
    ingredients = [
        ['碎牛肉', 226.79616, [1.27, 0.1, 0, 0.08585000000000001]],
        ['食盐', 6.083333333333333, [0, 0, 0, 0]],
        ['黑胡椒', 1.0374999999999999, [1.255 , 0.0163, 0.19325, 0.05195]],
        ['卡真调味料', 4, [0.46604999999999996, 0.010249999999999999, 0.06565, 0.0191]],
        ['马苏里拉芝士', 28.34952, [1.5, 0.11175, 0.01095, 0.11085]],
        ['切达芝士', 56.69904, [2.02, 0.16655, 0.015449999999999998, 0.11435000000000001]],
        ['黄油', 14.1875, [3.585, 0.40555, 0.0003, 0.00425]],
        ['熟培根', 28, [2.74, 0.21635000000000001, 0.006750000000000001, 0.17864999999999998]]
    ]
    
    # 初始化求解器
    solver = pywraplp.Solver('ScaleIngredients', pywraplp.Solver.GLOP_LINEAR_PROGRAMMING)

    # 1. 计算无缩放基准总营养
    base_nutrients = get_base_nutrient_sum(ingredients)
    print(f"无缩放基准总营养: {base_nutrients}")

    # 2. 定义唯一决策变量:缩放系数k
    k = solver.NumVar(0, 2, 'scaling_factor')

    # 3. 添加各营养素的范围约束:base_nutrients[i] * k 落在 [min, max] 区间
    for i in range(4):
        nutrient_name, min_val, max_val = nutrients[i]
        solver.Add(base_nutrients[i] * k >= min_val)
        solver.Add(base_nutrients[i] * k <= max_val)

    # 4. 计算各营养素的中位数目标值
    targets = [(n[1] + n[2])/2 for n in nutrients]

    # 5. 定义偏差变量处理绝对值,线性化目标函数(最小化总相对偏差)
    total_deviation = 0
    for i in range(4):
        # 正负偏差变量
        dev_plus = solver.NumVar(0, solver.infinity(), f'dev_plus_{i}')
        dev_minus = solver.NumVar(0, solver.infinity(), f'dev_minus_{i}')
        # 约束:实际值 = 目标值 + 正偏差 - 负偏差
        solver.Add(base_nutrients[i] * k == targets[i] + dev_plus - dev_minus)
        # 累加相对偏差,避免高数值营养素权重过大
        total_deviation += (dev_plus + dev_minus) / targets[i]

    # 6. 设定目标:最小化总偏差
    solver.Minimize(total_deviation)

    # 求解
    status = solver.Solve()

    if status == solver.OPTIMAL:
        optimal_k = k.solution_value()
        print(f"\n最优缩放系数: {optimal_k}")
        print("缩放后各营养素含量:")
        for i in range(4):
            actual = base_nutrients[i] * optimal_k
            print(f"{nutrients[i][0]}: {actual:.4f} (目标中位数: {targets[i]:.4f}, 允许范围: [{nutrients[i][1]}, {nutrients[i][2]}])")
    else:
        print("无可行解,请检查营养素上下限设置是否合理")

if __name__ == '__main__':
    main()

运行结果说明

运行代码后会直接输出最优缩放系数,以及缩放后的各营养素数值,所有结果都会自动符合设定的范围约束,且尽可能接近各营养素的中位数目标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 09:36:08