【问题标题】:Custom heuristic in ECLiPSe CLPECLiPSe CLP 中的自定义启发式
【发布时间】:2016-05-23 11:37:05
【问题描述】:

考虑以下谜题:

一个单元格被标记或未标记。谜题右侧和底部的数字表示特定行或列的总和。单元格对其行和列的总和有贡献(如果标记):位置 (i,j) 的单元格对列总和贡献 i,对行总和贡献 j。比如上图的第一行,标记了第 1、2、5 个单元格。它们对行总和贡献 1 + 2 + 5(因此总计 8),对它们的列总和贡献 1。

我在 ECLiPSe CLP 中有一个求解器来解决这个难题,我很想为它编写一个自定义启发式算法。

我认为最容易开始的单元格是那些列和行提示尽可能低的单元格。一般来说,N 越低,将N 写为 1 和N 之间的自然数之和的可能性就越小。在这个谜题的上下文中,这意味着具有最低column hint + row hint 的单元格出错的可能性最低,因此回溯更少。

在实现中,我有一个代表棋盘的NxN 数组,以及两个代表提示的大小为 N 的列表。 (侧面和底部的数字。)

我看到两个选项:

  • search/6 编写自定义选择谓词。但是,如果我理解正确的话,我只能给它2个参数。没有办法计算给定变量的行+列总和,因为我需要能够将它传递给谓词。我需要 4 个参数。

  • 忽略 search/6 并编写自己的标记方法。我就是这样 现在就可以了,请看下面的代码。

它采用棋盘(包含所有决策变量的 NxN 数组)、提示列表和返回包含所有变量的列表,现在根据它们的行 + 列总和进行排序。 但是,如您所见,这可能不会变得更麻烦。为了能够排序,我需要将总和附加到每个变量,但为了做到这一点,我首先需要将其转换为还包含所述变量坐标的术语,以便我转换回变量为排序完成后...

lowest_hints_first(Board,RowArr,ColArr,Out) :-
    dim(Board,[N,N]),
    dim(OutBoard,[N,N]),
    ( multifor([I,J],[1,1],[N,N]), foreach(Term,Terms), param(RowArr,ColArr) do
        RowHint is ColArr[I],
        ColHint is RowArr[J],
        TotalSum is RowHint + ColHint,
        Term = field(I,J,TotalSum)
    ),
    sort(3,<,Terms,SortedTerms), % Sort based on TotalSum
    terms_to_vars(SortedTerms,Board,Out), % Convert fields back to vars...
    ( foreach(Var,Out) do
         indomain(Var,max)
    ).

terms_to_vars([],_,[]).
terms_to_vars([field(I,J,TotalSum)|RestTerms],Vars,[Out|RestOut]) :-
    terms_to_vars(RestTerms,Vars,RestOut),
    Out is Vars[I,J].

最后,这个启发式算法几乎没有比 input_order 快。我怀疑这是因为它的实施方式很糟糕。关于如何做得更好的任何想法?还是我认为这种启发式应该是一个巨大的改进的感觉是不正确的?

【问题讨论】:

  • 要评估您的启发式方法,首先要做的是比较回溯的数量。当使用search/6 时,您可以使用backtrack(Count) 选项来获取此号码。使用您自己的搜索策略,请参阅 eclipseclp.org/doc/tutorial/tutorial088.html#toc82 了解如何计算等效计数。
  • 这是个好主意。我将为我自己的搜索实现它,尽管使用search/6 并将它传递给我自己的搜索谓词会更容易。当您将输入传递给所述谓词时,您有什么想法可以完成这项工作吗?我无法让它仅使用 search/6 需要的 2 个参数谓词。
  • 您可以在代码中调用search/6 来代替foreach(Var,Out) 循环。
  • 顺便说一句,您的排序应该类似于sort(3,=&lt;,Terms,SortedTerms),否则您将丢失具有非唯一排序键(TotalSum)的列表元素。
  • 非常感谢您的帮助。我实现了你链接的教程,它一直为高达 250x250 的谜题提供 0 个回溯,我认为这非常奇怪。事实证明,其他变量选择启发式方法也使用 0 个回溯。那是search/6,所以它不能是回溯实现。令我惊讶的是,在这种情况下,约束传播是如此强大。

标签: prolog clpfd eclipse-clp


【解决方案1】:

我看到您已经对 Joachim 提出的改进感到满意;但是,当您要求进一步改进启发式算法时,请考虑只有一种方法可以得到 0 作为总和,也只有一种方法可以得到 15。 只有一种方法可以得到 1 和 14、2 和 13;获得 3 和 12 的两种方法。 一般来说,如果你有 K 种方法来获得总和 N,那么你也有 K 种方法来获得 15-N。

因此,困难的金额不是大的,而是中等的。

【讨论】:

  • 你说得对。我忘了考虑列数限制了选择。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-15
  • 1970-01-01
  • 2013-05-27
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多