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

如何在Google OR-Tools中实现高精度资源分配误差最小化模型

问题定义

我需要对资源进行分组,让每组的平均价格尽可能接近给定的目标平均价格。输入是包含价格和数量的资源列表,以及目标分组的数量和平均价格,最终要把资源数量分配到各组,使每组实际平均价格与目标价格的偏差最小。

我将这个问题建模为误差最小化问题,约束条件包括:

  • 所有资源数量必须被完全分配
  • 资源总数量 = 目标分组总数量

我已经用Choco Solver实现了该模型,但它使用integer类型存储变量,无法满足实际场景的精度需求(实际价格含小数,需缩放为整数处理)。现在我想把模型迁移到支持long类型的Google OR-Tools以提升精度,但不知道如何在OR-Tools的API中定义需要最小化的误差函数,求相关实现经验。

模型定义

R = 输入资源集合,
G = 输出分组集合,

Rq = 资源数量,
Rp = 资源价格,

Gq = 分组目标数量,
Gp = 分组目标平均价格

待计算变量:分配给分组j的资源i的数量RiGj

约束条件

// 每组分配到的资源数量总和等于该组的目标数量
Gjq = SUM(RiGj)

// 每个资源分配出去的数量总和等于该资源的可用数量
Riq = SUM(RiGj)

// 每组的价格偏差计算
Ej = ABS(SUM(RiGj * Rip)/Gjq - Gjp)

求解目标:最小化所有分组的偏差总和SUM(Ej)

可运行的Choco解决方案

Model model = new Model();
IntVar[] vars = new IntVar[resources.length * groups.length];

ArExpression[] groupQtyConstraint = new ArExpression[groups.length];
ArExpression[] resourceQtyConstraint = new ArExpression[resources.length];
ArExpression[] error = new ArExpression[groups.length];

for (int i = 0; i < groups.length; i++) {
  for (int j = 0; j < resources.length; j++) {
    // 变量定义
    IntVar curr = model.intVar(0, resources[j].quantity().intValue());
    vars[i * resources.length + j] = curr;

    // 构建分组数量约束
    if (groupQtyConstraint[i] == null) {
      groupQtyConstraint[i] = curr;
    } else {
      groupQtyConstraint[i] = groupQtyConstraint[i].add(curr);
    }

    // 构建资源数量约束
    if (resourceQtyConstraint[j] == null) {
      resourceQtyConstraint[j] = curr;
    } else {
      resourceQtyConstraint[j] = resourceQtyConstraint[j].add(curr);
    }

    // 构建平均价格计算逻辑
    // TODO: 此处存在精度问题 - int类型精度不足
    if (error[i] == null) {
      error[i] = curr.mul(resources[j].price());
    } else {
      error[i] = error[i].add(curr.mul(resources[j].price()));
    }
  }
  model.arithm(groupQtyConstraint[i].intVar(), "=", groups[i].quantity()).post();
}

for (int i = 0; i < resources.length; i++) {
  model.arithm(resourceQtyConstraint[i].intVar(), "=", resources[i].quantity()).post();
}

ArExpression objective = null;
for (int i = 0; i < groups.length; i++) {
  error[i] =
      error[i]
          .div(groups[i].quantity())
          .sub(groups[i].price())
          .abs();

  if (objective == null) {
    objective = error[i];
  } else {
    objective = objective.add(error[i]);
  }
}

// 寻找最小化误差的最优解
Solver solver = model.getSolver();
Solution optimalSolution = solver.findOptimalSolution(objective.intVar(), Model.MINIMIZE);
示例

输入

资源列表: [
  ("R1", 12, 103.5),
  ("R2", 6, 102.45),
  ("R3", 2, 100.10)
]

分组列表: [
  ("G1", 6, 102.5833),
  ("G2", 14, 102.9571)
]

最优解

"G1": [
  ("R1", 3),
  ("R2", 2),
  ("R3", 1)
]

"G2": [
  ("R1", 9),
  ("R2", 4),
  ("R3", 1)
]

注:本示例中已将价格乘以10000转换为整数处理。

核心疑问

我无法理清如何在OR-Tools中定义并最小化如下误差函数:
Ej = ABS(SUM(RiGj * Rip)/Gjq - Gjp)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:42:13