使用约束java设置分区

时间:2014-01-31 20:59:49

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

什么

我正在尝试为锦标赛制作一套最佳括号(最佳约束条件)。

问题

我不知道如何处理这个问题。 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个大小的集合。

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

再次感谢您的时间!

2 个答案:

答案 0 :(得分:5)

这是约束编程方法的概念验证。它是在MiniZinc中完成的(通常在我对CSP问题进行原型设计时)。我没有在任何Java系统中实现它,但希望它有一些用处。

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

以下是主要方法:

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

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

    “set_size”上的对称性破坏:

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

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

  • 通过最大化4号和8号支架的数量来实现4和8尺寸支架的优先选择(两者的重量均为1,其他支架尺寸的重量为0);这是“z”变量。另一种方法是将支架尺寸的重量减少8乘2和尺寸4的1(以及所有其他重量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秒。

答案 1 :(得分:0)

由于您将Java视为关键字,因此您可能需要调查Java解算器,它应该能够处理分区问题:

  • OptaPlanner
  • JaCop
  • ECLiPSe CLP
  • 巧克力
  • JS​​R-331
  • OR-tools(需要安装非JVM代码)
  • ...