ECLiPSe CLP中的自定义启发式

时间:2016-05-23 11:37:06

标签: prolog clpfd eclipse-clp

考虑以下难题:

Kakurasu

单元格已标记或未标记。拼图右侧和底侧的数字表示某行或列的总和。单元格对其行和列中的总和做出贡献(如果已标记):位置(i,j)中的单元格对列值求和,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个参数。

  • 忽略搜索/ 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快。我怀疑它是由于它实施的可怕方式。关于如何做得更好的任何想法?或者我觉得这种启发式应该是一个巨大的改进不正确?

1 个答案:

答案 0 :(得分:2)

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

所以困难的数字不是大的,它们是中间的。