操作Prolog代码输出

时间:2017-09-11 14:41:42

标签: prolog clpfd

我正在尝试在此页面上运行代码:Linux终端上的swipl中的https://swish.swi-prolog.org/example/clpfd_queens.pl

:- use_module(library(clpfd)).

n_queens(N, Qs) :-
    length(Qs, N),
    Qs ins 1..N,
    safe_queens(Qs).

safe_queens([]).
safe_queens([Q|Qs]) :-
    safe_queens(Qs, Q, 1),
    safe_queens(Qs).

safe_queens([], _, _).
safe_queens([Q|Qs], Q0, D0) :-
    Q0 #\= Q,
    abs(Q0 - Q) #\= D0,
    D1 #= D0 + 1,
    safe_queens(Qs, Q0, D1).

以下命令有效:

?- n_queens(4, Qs), labeling([ff], Qs).

但不只是n_queens(4, Qs)

?- n_queens(4, Qs).
Qs = [_G1470, _G1473, _G1476, _G1479],
_G1470 in 1..4,
abs(_G1470-_G1479)#\=3,
_G1470#\=_G1479,
abs(_G1470-_G1476)#\=2,
_G1470#\=_G1476,
abs(_G1470-_G1473)#\=1,
_G1470#\=_G1473,
_G1479 in 1..4,
abs(_G1476-_G1479)#\=1,
_G1476#\=_G1479,
abs(_G1473-_G1479)#\=2,
_G1473#\=_G1479,
_G1476 in 1..4,
abs(_G1473-_G1476)#\=1,
_G1473#\=_G1476,
_G1473 in 1..4.

为什么需要labeling部分?没有labeling部分可以获得正确的输出吗?

对于较大的数字,只能获得解决方案的初始部分:

?- n_queens(20, Qs), labeling([ff], Qs).
Qs = [1, 3, 5, 14, 17, 4, 16, 7, 12|...] ;
Qs = [1, 3, 5, 18, 16, 4, 10, 7, 14|...] ;
...

如何获得更大数字的完整列表输出?此外,如何将所有数字组合在一起,而无需为每个解决方案按空格键?谢谢你的帮助。

1 个答案:

答案 0 :(得分:2)

n_queens/2 解决了 N 皇后的 N - 问题:它构造约束编程问题:它构造 N 变量(皇后的列),并在这些皇后之间添加约束:例如,两个皇后不能放在同一行上,也不能放在同一对角线上。如果我们将问题输出重写为更方便的输出,我们就会看到这一点:

A in 1..4,
abs(A-D)#\=3,
A#\=D,
abs(A-C)#\=2,
A#\=C,
abs(A-B)#\=1,
A#\=B,
D in 1..4,
abs(C-D)#\=1,
C#\=D,
abs(B-D)#\=2,
B#\=D,
C in 1..4,
abs(B-C)#\=1,
B#\=C,
B in 1..4.

所以我们看到四个皇后(ABCD)。每个皇后都应该在域1..4中,此外我们会看到不相等的约束,例如A #\= D,以防止第一个女王A与最后一个女王D共享一列。我们终于看到像abs(A-C) #\= 2这样的约束来阻止第一个女王A和第三个女王C两个不同的列(诊断攻击)。

下一个labeling/2实际上解决问题:它执行放宽(减少域)以及分支(为变量选择值或子范围值)以及回溯以防万一约束失败了。它将一直持续到找到解决方案,我们可以使用Prolog的回溯机制让labeling/2提出更多解决方案。

labeling因此给出了一个变量列表,旨在标记它们:为它们分配一个超出范围的值,以便满足所有约束条件。

因此,与实际求解部分相比,问题构造部分通常非常快:很容易生成 O(N)变量和 O(N 2 约束,但可能需要指数的时间 O(D N 来提出满足所有约束条件的解决方案。

  

此外,如何将所有数字组合在一起,而无需为每个解决方案按空格键?

您可以使用元谓词findall/3

all_n_queens(N,LL) :-
    findall(L,(n_queens(N,L), labeling([ff], L)),LL).

生成:

?- all_n_queens(5,LL).
LL = [[1, 3, 5, 2, 4], [1, 4, 2, 5, 3], [2, 4, 1, 3, 5], [2, 5, 3, 1, 4], [3, 1, 4, 2|...], [3, 5, 2|...], [4, 1|...], [4|...], [...|...]|...].
  

如何获得更大数字的完整列表输出?

您可以设置answer_write_options标志:

?- set_prolog_flag(answer_write_options,[max_depth(0)]).
true.

?- all_n_queens(5,LL).
LL = [[1,3,5,2,4],[1,4,2,5,3],[2,4,1,3,5],[2,5,3,1,4],[3,1,4,2,5],[3,5,2,4,1],[4,1,3,5,2],[4,2,5,3,1],[5,2,4,1,3],[5,3,1,4,2]].
相关问题