【问题标题】:Set partitioning with constraints java使用约束java设置分区
【发布时间】:2014-02-24 17:31:32
【问题描述】:

什么

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

问题

我不知道如何解决这个问题。 This 论文水平相当高,但讨论了使用约束规划解决集合分区问题的可能性。它还指出,大多数集合分区问题都是通过整数规划解决的。我主要是在寻找一个可以效仿的例子。问题类似于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 个大小的集合。

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

再次感谢您的宝贵时间!

【问题讨论】:

  • 它至少可以帮助我举一些你所追求的例子。在那之前,这里有一些 CP 模型的链接(用不同的系统编写)解决了一个简单的集合分区问题:hakank.org/common_cp_models/#setpartition
  • 嗨@hakank,我已经编辑了我的问题,希望为您提供我正在寻找的更好的例子。我查看了您的示例,它们似乎都分为预定义数量的子集。如果我需要详细说明我的示例,请告诉我。

标签: java dynamic-programming constraint-programming integer-programming


【解决方案1】:

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

  • OptaPlanner
  • 贾科普
  • ECLiPSe CLP
  • 巧克力
  • JSR-331
  • OR-tools(需要安装非JVM代码)
  • ...

【讨论】:

  • 像 Eclipse 这样的 IDE 如何解决寻找这种算法的问题? (除了编辑辅助)
  • 我认为 Geoffrey 指的是 ECLiPSe CLP,而不是 IDE。我会将 Google or-tools/Java 添加到 Java 求解器列表中。
  • @hakank 相应地更新了答案(如果需要,请随时进一步编辑:)
  • @hakank 是 OR-tools 100% 纯 Java(所以它可以作为没有本地 jar 的仅 jar 分发)吗?或者让我换个说法:它可以在任何 JVM 上运行而无需额外的分期付款吗?
  • @GeoffreyDeSmet:or-tools 不是纯 Java。该引擎是用 C++ 编写的,因此也必须安装它。
【解决方案2】:

这是约束编程方法的概念验证。它是在 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]

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

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

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

 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 秒内解决了这个问题。

【讨论】:

  • 这太棒了!谢谢@hakank!有趣的是,您仍然必须预先定义最大组数。我很难对问题的这方面进行建模。你非常有帮助。再次感谢!
  • 很高兴能为您提供帮助,亚历克斯。 MiniZinc 要求所有数组都具有固定大小,因此我将其定义为最大可能值(N div 2,允许的最小集合大小),部分原因是出于效率原因。
猜你喜欢
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 2012-12-08
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多