【问题标题】:3-in-a-row logic puzzle: optimisation for sequence constraints in lists/arrays3-in-a-row 逻辑谜题:优化列表/数组中的序列约束
【发布时间】:2016-03-24 14:16:47
【问题描述】:

在下面的谜题中,我们尝试用蓝白方块填充网格,这样:

  • 不允许使用相同颜色的 3 行(或列)。
  • 每一行和每一列都有相同数量的蓝色和白色方块。

如果我们现在用 0 表示白色,用 1 表示蓝色,我们得到:

0 _ _ _ 1 _
_ 0 _ _ _ _
_ _ _ _ _ 0
1 _ _ 0 _ _
_ _ 1 1 _ _
_ 0 _ _ 1 _

我们可以很快验证

0 1 0 0 1 1 
0 0 1 1 0 1 
1 1 0 1 0 0 
1 1 0 0 1 0 
0 0 1 1 0 1 
1 0 1 0 1 0 

是这个例子的解决方案。

作为约束,我写了以下内容:

constraints(Board,N) :-
    N2 is N // 2,
    ( for(I,1,N), param(Board,N2,N)
    do
      Row is Board[I,1..N],
      Col is Board[1..N,I],
      ic_global:sequence_total(N2,N2,1,2,3,Row),
      ic_global:sequence_total(N2,N2,1,2,3,Col)
    ).

sequence_total/6 确保值 1 应在行/列中恰好出现 N2 次(N 的一半),并且指定行/列中的 3 个元素的每个序列应包含该值的 1 到 2 倍1(因此没有 3 个值为 1 的方格可以相邻出现)。

对于 18x18 拼图实例 (*),我得到以下结果:

Solved in 147 backtracks
Yes (10.39s cpu, solution 1)

看起来约束在执行任何搜索之前已经很好地完成了它们的工作,因为“只”需要 147 个回溯。然而,运行时间对我来说似乎真的很长,尤其是与回溯的数量相比。我猜这是由于必须进行的所有序列检查?更改search/6 中的任何选择/选择方法对运行时间几乎没有任何影响这一事实似乎证实了这一点。

如果是这样,是否有任何其他更有效的方法来约束列表/数组中的序列不具有相邻的 N 个相同元素并提高运行时间?

编辑

使用下面@jschimpf提供的分解版本后,得到如下结果:

Solved in 310 backtracks
Yes (0.22s cpu, solution 1)

新的约束没有sequence/6强,我们确实需要更多的回溯,但是我们的运行时间从10.39秒下降到了0.22秒,所以总体结果非常理想。

样本数据:

用于此问题的谜题(无需回溯即可解决)

问题(p(6,1),[(1,1,0),(1,5,1),(2,2,0),(3,6,0),(4,1, 1),(4,4,0),(5,3,1),(5,4,1),(6,2,0),(6,5,1)])。

我发布结果的谜题 (*):

问题(p(18,1),[(1,3,0),(1,9,0),(1,10,0),(1,12,0),(1,14, 0),(1,18,1),(2,4,0),(2,7,1),(2,8,1),(3,2,1),(3,6,0) ,(3,16,0),(3,17,0),(4,2,1),(4,4,1),(4,10,1),(4,13,1),( 4,18,1),(5,8,1),(5,10,1),(5,15,0),(5,16,1),(6,12,1),(7, 3,0),(7,4,0),(7,6,1),(7,9,0),(7,12,1),(7,17,0),(8,1, 1),(8,4,0),(8,8,1),(8,15,1),(8,16,1),(9,7,0),(9,10,0) ,(9,14,0),(10,2,1),(10,4,1),(10,6,1),(10,13,1),(11,7,0),( 11,10,1),(12,1,1),(12,4,1),(12,7,1),(12,15,1),(12,16,1),(13, 1,1),(13,6,0),(13,8,1),(13,10,0),(13,16,1),(14,5,1),(14,10, 0),(14,13,1),(15,1,1),(15,3,1),(15,12,0),(15,13,​​1),(15,15,0) ,(16,2,1),(16,4,0),(16,12,0),(16,18,0),(17,9,0),(17,15,0),( 17,18,0),(18,2,1),(18,8,1),(18,11,1),(18,15,1),(18,16,1)])。

【问题讨论】:

  • 好问题,+1!您能否提供一些示例实例?
  • 谢谢。我已经编辑了答案。
  • 谢谢。如果可能,请使用三元术语来表示给定。目前,您正在使用例如','(1,','(1,0)),即嵌套的“ands”,也称为“and-lists”。更简洁的表示例如:x_y_v(1, 1, 0).
  • 我不知道这一点,但考虑到标准列表构造函数,这是有道理的。这意味着 (1, 2, 3) = (X, Y) 将评估为真,我可以看到这会产生意想不到的结果.. 感谢您的提示!
  • 使用(-)/2 表示对——而不是','/2(.)/2!这个约定被许多库谓词处理对使用,因为它结合了简洁的语法和高效的存储——大多数 Prolog 系统foo-bar[foo,bar] 占用更少的内存。 对于三元组,请遵循 @mat 的建议!

标签: prolog constraints constraint-programming eclipse-clp clp


【解决方案1】:

事实证明,在这种情况下,sequence 约束的手工分解版本效率更高。使用示例

sequence_1_2([X1,X2,X3|Xs]) :- !,
    S #:: 1..2,
    X1+X2+X3 #= S,
    sequence_1_2([X2,X3|Xs]).
sequence_1_2(_).

将任何 3 元素子序列的总和约束为 1 或 2,并将 sequence_total/6 约束替换为

    ...,
    sum(Row) #= N2,
    sequence_1_2(Row),

这将求解时间缩短至 0.2 秒。

【讨论】:

    猜你喜欢
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 2012-01-17
    • 1970-01-01
    • 2013-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多