Prolog通过列表列表递归

时间:2016-05-12 04:50:01

标签: recursion prolog

我正在尝试一个说明以下内容的序言:

魔方是3×3矩阵的不同数字(1到9之间),所有行和列加起来相同(但不一定是对角线)。例如: 2 7 6 9 5 1 4 3 8 是一个神奇的广场。 我们将Prolog中的正方形表示为3×3矩阵,即列表[R1,R2,R3],其中每个R_i是三个数字的列表。例如, 上述魔方的表示是 [[2,7,6],[9,5,1],[4,3,8]]

定义一个谓词魔法/ 1,用于测试地面3×3矩阵(即 所有条目都是数字的地方)是一个魔术广场。

我已经通过以下方式完成了这项工作,而且我很确定如果我在考试中也这样做也是允许的,但对我来说这似乎是一种黑客攻击:

magic([[A,B,C], [D,E,F], [G,H,I]]) :- 
                Y is A + B + C, 
                Y is D + E + F, 
                Y is G + H + I, 
                Y is A + D + G,
                Y is B + E + H,
                Y is C + F + I.

我想要的方法是递归外部列表中的每个列表,然后总结一下。对于外部列表中的每个列表,它们应该总结为相同的值(我认为15实际上是这个“魔术”矩阵的唯一可能解决方案)。同样,我对列做同样的事情(取每个列表的第一个,第二个和第三个并分别加起来)。但是,我并不完全确定如何做后者,因为我没有使用列表列表。如果有人能就这些计算如何进行整体解决,我将不胜感激。

由于

1 个答案:

答案 0 :(得分:0)

请注意,您的解决方案不会检查A,..,I值是否相同且在1..9范围内。这是针对N>的N×N平方的解决方案。 2:

magic(L) :-
    magic_range(L),
    magic_sum(S, L),
    magic_line(S, L),
    transpose(L, T),
    magic_line(S, T).

% S value from https://oeis.org/A006003
magic_sum(S, L) :-
    length(L, N),
    S is N * (N*N + 1) / 2.

magic_range(L) :-
    flatten(L, F),
    sort(F, S),
    length(L, N),
    N2 is N * N,
    numlist(1, N2, S).

magic_line(_, []).
magic_line(S, [A | As]) :-
    sumlist(A, S),
    magic_line(S, As).

% https://github.com/SWI-Prolog/swipl-devel/blob/9452af09962000ebb5157fe06169bbf51af5d5c9/library/clp/clpfd.pl#L6411
transpose(Ls, Ts) :-
    must_be(list(list), Ls),
    lists_transpose(Ls, Ts).

lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
    foldl(transpose_, L, Ts, [L|Ls], _).

transpose_(_, Fs, Lists0, Lists) :-
    maplist(list_first_rest, Lists0, Fs, Lists).

list_first_rest([L|Ls], L, Ls).

一些查询

?- magic([[1,1,1],[1,1,1],[1,1,1]]).
false.

?- magic([[2,7,6],[9,5,1],[4,3,8]]).
true ;
false.

?- magic([[16,3,2,13], [5,10,11,8], [9,6,7,12], [4,15,14,1]]).
true ;
false.

transpose谓词是最复杂的部分。有关其他选择,请参阅here