Prolog求解N皇后问题时仅失败一次即终止,原因何在?
分析你的N皇后问题代码问题
嗨,我来帮你排查这个问题~你的代码核心问题是缺少皇后位置的生成逻辑,导致Prolog没有候选的位置可以回溯尝试,直接因为自由变量的意外绑定而失败。
为什么你的代码会直接返回false?
当你执行n_queens(8, Ans)时:
length(Ans, 8)只是创建了一个包含8个自由变量的列表,这些变量没有任何约束(比如X/Y应该在1-8之间)。- 进入
queens_are_safe检查时,第一个皇后是_X1/_Y1,第二个是_X2/_Y2。当检查not(same_column(_X1/_Y1, _X2/_Y2))时,Prolog会先尝试满足same_column的条件——也就是把_X1和_X2绑定成同一个值(比如调试里的_15108),然后not(...)就会失败。 - 关键是:你的代码没有告诉Prolog“去尝试其他不同的X值”,因为没有生成候选位置的逻辑,所以没有回溯的空间,直接返回false。
修正后的代码及解释
我帮你调整了代码,添加了位置生成逻辑,同时修正了对角线判断的小错误:
n_queens(NumQueens, Answer) :- length(Answer, NumQueens), % 给每个皇后生成合法的位置(行和列都在1到NumQueens范围内) maplist(queen_position(NumQueens), Answer), queens_are_safe(Answer). % 生成单个皇后的合法位置:X和Y都是1到NumQueens的整数 queen_position(NumQueens, X/Y) :- between(1, NumQueens, X), between(1, NumQueens, Y). queens_are_safe([]). queens_are_safe([Queen | Queens]) :- queen_is_safe(Queen, Queens), queens_are_safe(Queens). queen_is_safe(_, []). queen_is_safe(NewQueen, [Queen | Queens]) :- not(same_column(NewQueen, Queen)), not(same_row(NewQueen, Queen)), not(diagonal(NewQueen, Queen)), queen_is_safe(NewQueen, Queens). % 修正对角线判断:用=:=做算术比较,并且取绝对值覆盖两个对角线方向 diagonal(X/Y, X1/Y1) :- abs(Y1 - Y) =:= abs(X1 - X). same_column(X/_, X/_). same_row(_/Y, _/Y).
关键修正点:
- 添加位置生成逻辑:
queen_position/2结合maplist/2,给每个皇后生成1到NumQueens之间的X/Y坐标,这样Prolog有大量候选值可以回溯尝试,而不是用无约束的自由变量。 - 修正对角线判断:原来的
Y1 - Y = X1 - X用的是Prolog的统一绑定(=),这会把变量绑定成相等的表达式,而不是做算术比较。应该用=:=来判断数值相等,并且取绝对值,这样能覆盖左上到右下、右上到左下两种对角线情况。
现在你再执行n_queens(8, Ans).,Prolog就会开始枚举所有可能的位置组合,找到满足安全条件的解,甚至可以通过按;来查看更多解。
内容的提问来源于stack exchange,提问作者PopKernel
相关产品推荐
相关产品推荐

