这是约束编程方法的概念验证。它是在 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”上打破对称性:
然后是三个大小为 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
这是运行给出的示例的输出:
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 秒内解决了这个问题。