我正在尝试在此页面上运行代码: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|...] ;
...
如何获得更大数字的完整列表输出?此外,如何将所有数字组合在一起,而无需为每个解决方案按空格键?谢谢你的帮助。
答案 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.
所以我们看到四个皇后(A
,B
,C
和D
)。每个皇后都应该在域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]].