5

什么

我正在尝试为锦标赛制作一组最佳括号(由约束定义的最佳)。

问题

我不知道如何解决这个问题。 这篇论文水平很高,但讨论了用约束规划解决集合分区问题的可能性。它还指出,大多数集合分区问题都是通过整数规划解决的。我主要是在寻找一个可以效仿的例子。这个问题类似于这个SO question。我见过的大多数约束示例都定义了特定的分区总数。是否可以建模一个系统,其中分区将由约束和参与者集动态确定?我会链接示例,但由于我的声誉,我仅限于 2 个。

一个更具体的例子

已知值

  • 参加人数为 N。
  • 每个参与者都有一个与他们相关的权重 W。

约束

  • 一个支架(组)由 2、3、4、6、7 或 8 名参与者组成。
  • 每个参与者仅在一个括号中。
  • 括号中权重最低的参与者和权重最高的参与者之间的差异不得超过 15%。
  • 与所有其他支架尺寸相比,更倾向于创建尺寸为 8 和 4 的支架。

例如,假设有 8 个参与者。

{ {1, W=100}, {2, W=103}, {3, W=105}, {4, W=106}, {5, W=110}, {6, W=114}, { 7, W=120}, {8, W=125} }

一种可能的解决方案是:{1, 2, 3}, {4, 5}, {6, 7, 8}

一个更优化的解决方案是:{1, 2, 3, 4}, {5, 6, 7, 8},因为与之前的解决方案相比,这有利于 4、8 个大小的集合。

是否可以将一个集合划分为动态数量的子集合?

感谢你的宝贵时间!

4

2 回答 2

5

这是约束编程方法的概念验证。它是在 MiniZinc 中完成的(就像我为 CSP 问题制作原型时一样)。我还没有在任何 Java 系统中实现它,但希望它还是有用的。

MiniZinc 模型在这里:http ://www.hakank.org/minizinc/bracket_partitioning.mzn

这是主要的方法:

  • 大小为 1..N 的数组 ("x") 用于将人 (x[i]) 分配到哪个括号。在 "x" 上打破对称性:

    • 括号 1 必须在括号 2 之前使用(约束 value_precede_chain)
  • 1..N div 2 的另一个数组(“set_size”)包含每个括号中的人数。

    在“set_size”上打破对称性:

    • “set_size”中的值必须按降序排列。
  • 然后是三个大小为 1..N div 2(即与“set_size”相同)的帮助数组(“mins”、“maxs”、“diffs”),其中包括每个括号的最小值、最大值,以及maxs[s]-mins[s] 之间的差异 (diff[s])。此差异必须在 15% 以内(计算为“10000*diffs[s] div maxs[s] <= 1500”)。

    这 15% 的要求使模型有点混乱,但很有趣。

  • 4 和 8 尺寸括号的偏好已通过最大化 4 和 8 尺寸括号的数量来实现(两者的权重均为 1,其他括号尺寸的权重为 0);这是“z”变量。另一种方法是对 8 x 2 的支架尺寸和 1 的 4 尺寸(以及所有其他重量为 0)进行加权,因此比 4 个尺寸的支架更喜欢 8 个尺寸的支架。

注意: - 还有一些其他约束 - 隐式约束和对称性破坏 - 往往会加速模型,例如:

 sum(set_size) = n % implicit constraint

 x[1] = 1 % assign the first person to bracket 1
  • 该代码还包括一些用于随机测试的东西,例如 rand_int_array (MiniZinc 没有内置的)。这可以忽略。

  • 我不知道现实生活中 N 可以有多大。也许它非常大,然后必须添加更多的对称性破坏等或使用另一种方法。

这是运行给出的示例的输出:

w: [100, 103, 105, 106, 110, 114, 120, 125]
z: 2
x: [1, 1, 1, 1, 2, 2, 2, 2]
set_size: [4, 4, 0, 0]
diffs: [6, 15, 0, 0]
mins: [100, 110, 0, 0]
maxs: [106, 125, 0, 0]
bracket 1: [100, 103, 105, 106]
bracket 2: [110, 114, 120, 125]

在这里,我们看到两个大小为 4 的括号具有预期的最佳值(z=2,因为有 2 个大小为 4)。

对于 N=28 的另一个示例,模型给出了这个结果(“w”是“随机”权重的数组)。

w: [111, 109, 112, 146, 115, 103, 130, 145, 128, 127, 144, 114, 133, 126, 134, 133, 114, 134, 143, 116, 106, 104, 147, 110, 114, 102, 118, 130]
z: 7
x: [1, 1, 1, 2, 1, 3, 2, 2, 2, 4, 4, 3, 4, 4, 5, 6, 3, 5, 5, 3, 7, 7, 5, 7, 6, 7, 6, 6]
set_size: [4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0]
diffs: [6, 18, 13, 18, 13, 19, 8, 0, 0, 0, 0, 0, 0, 0]
mins: [109, 128, 103, 126, 134, 114, 102, 0, 0, 0, 0, 0, 0, 0]
maxs: [115, 146, 116, 144, 147, 133, 110, 0, 0, 0, 0, 0, 0, 0]
bracket 1: [111, 109, 112, 115]
bracket 2: [146, 130, 145, 128]
bracket 3: [103, 114, 114, 116]
bracket 4: [127, 144, 133, 126]
bracket 5: [134, 134, 143, 147]
bracket 6: [133, 114, 118, 130]
bracket 7: [106, 104, 110, 102]

Gecode 在大约 0.7 秒内解决了这个问题。

于 2014-02-03T18:19:37.523 回答
0

由于您将 Java 列为关键字,因此您可能想要研究 Java 求解器,它应该能够处理分区问题:

  • OptaPlanner
  • 贾科普
  • ECLiPSe CLP
  • 巧克力
  • JSR-331
  • OR-tools(需要安装非 JVM 代码)
  • ...
于 2014-02-01T10:03:43.917 回答