You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prolog新手求助:CLPFD实现无冲突主教放置及DFS求解问题

主教放置问题的约束建模

1. 变量定义

  • 针对n×n棋盘,共需放置2(n-1)个主教,每个主教的位置用二元组(R_i, C_i)表示(i从1到2(n-1))
  • 可拆分建模为两个变量列表:
    • R = [R₁, R₂, ..., R_{2n-2}]:每个元素对应一个主教的行号
    • C = [C₁, C₂, ..., C_{2n-2}]:每个元素对应一个主教的列号

2. 变量域

  • 所有行变量的域:1..n(棋盘行号范围)
  • 所有列变量的域:1..n(棋盘列号范围)

3. 约束条件

  • 对角线不冲突约束:任意两个主教不能处于同一条对角线上,即对任意i≠j:
    • R_i - C_i ≠ R_j - C_j(反对角线,斜率为1)
    • R_i + C_i ≠ R_j + C_j(主对角线,斜率为-1)
  • 注:该约束已隐含所有主教位置互不唯一,无需额外添加位置唯一性约束

n=3且首个主教置于(1,1)的DFS+前向检查解生成

n=3时需放置4个主教,首个位置固定为(1,1),剩余3个主教按行优先、同行列从小到大的DFS顺序搜索,结合前向检查(每放置一个主教就排除其攻击范围内的所有位置),解的生成顺序如下:

第一步:初始状态

已放置主教:(1,1)
排除的对角线:

  • 反对角线值1-1=0 → 排除位置(2,2),(3,3)
  • 主对角线值1+1=2 → 仅排除(1,1)(其他位置不满足R+C=2)
    剩余可选位置:(1,2),(1,3),(2,1),(2,3),(3,1),(3,2)

第二步:生成第一个完整解

  1. 第二个主教选择(1,2):
    • 验证:反对角线值1-2=-1,主对角线值1+2=3,与(1,1)无冲突
    • 前向检查:排除反对角线R-C=-1的(2,3),主对角线R+C=3的(2,1)
    • 剩余可选位置:(1,3),(3,1),(3,2)
  2. 第三个主教选择(1,3):
    • 验证:反对角线值1-3=-2,主对角线值1+3=4,与已放置的两个主教无冲突
    • 前向检查:排除主对角线R+C=4的(3,1)
    • 剩余可选位置:(3,2)
  3. 第四个主教选择(3,2):
    • 验证:反对角线值3-2=1,主对角线值3+2=5,与已放置的三个主教无冲突
    • 得到完整解:(1,1), (1,2), (1,3), (3,2)

第三步:回溯生成下一个解

回溯到第三个主教的候选,跳过(1,3)选择(3,1):

  1. 第三个主教选择(3,1):
    • 验证:反对角线值3-1=2,主对角线值3+1=4,与(1,1),(1,2)无冲突
    • 前向检查:无额外位置排除(剩余(3,2)不在其对角线上)
  2. 第四个主教选择(3,2):
    • 验证:无冲突
    • 得到完整解:(1,1), (1,2), (3,1), (3,2)

后续继续回溯,会生成其他合法解,比如(1,1), (1,3), (2,1), (3,2)等,均遵循DFS的行优先搜索顺序。


CLPFD在Prolog中的应用指导

CLPFD(Constraint Logic Programming over Finite Domains)是Prolog中处理约束满足问题的标准库,以下是针对本问题的具体应用步骤:

1. 导入CLPFD库

在代码开头添加:

:- use_module(library(clpfd)).

2. 变量与域建模

定义行、列变量列表,设置其域范围:

bishop_n(N, Rows, Cols) :-
    % 计算主教数量:2*(N-1)
    NumBishops is 2*(N-1),
    length(Rows, NumBishops),
    length(Cols, NumBishops),
    % 设置变量域
    Rows ins 1..N,
    Cols ins 1..N,
    % 后续约束...

3. 添加对角线约束

利用CLPFD的all_distinct/1约束,结合自定义的加减谓词,确保所有主教的对角线值唯一:

% 计算反对角线值R-C,确保互不相同
    maplist(sub, Rows, Cols, Diag1),
    all_distinct(Diag1),
    % 计算主对角线值R+C,确保互不相同
    maplist(add, Rows, Cols, Diag2),
    all_distinct(Diag2).

% 辅助谓词:计算A-B
sub(A, B, C) :- C #= A - B.
% 辅助谓词:计算A+B
add(A, B, C) :- C #= A + B.

注:#=是CLPFD的约束等式,而非普通Prolog的算术等式,能在搜索前进行约束传播。

4. 添加初始位置约束(以n=3,首个主教在(1,1)为例)

直接固定列表的第一个元素:

Rows = [1 | _],
    Cols = [1 | _],

5. 搜索解

使用labeling/2触发搜索,默认顺序即为DFS,CLPFD会自动进行前向检查(约束传播):

% 合并变量列表,统一搜索
    append(Rows, Cols, Vars),
    labeling([], Vars).

若要指定搜索策略,比如行优先,可调整labeling的选项,比如labeling([ff], Vars)(首次失败,提升搜索效率)。

完整示例代码(n=3)

:- use_module(library(clpfd)).

bishop_placement(Rows, Cols) :-
    % n=3,4个主教
    length(Rows, 4),
    length(Cols, 4),
    % 初始位置(1,1)
    Rows = [1 | _],
    Cols = [1 | _],
    % 域约束
    Rows ins 1..3,
    Cols ins 1..3,
    % 对角线约束
    maplist(sub, Rows, Cols, Diag1),
    all_distinct(Diag1),
    maplist(add, Rows, Cols, Diag2),
    all_distinct(Diag2),
    % 搜索解
    append(Rows, Cols, Vars),
    labeling([], Vars).

sub(A, B, C) :- C #= A - B.
add(A, B, C) :- C #= A + B.

调用bishop_placement(Rows, Cols).即可得到所有合法解,第一个返回的解与之前DFS生成的第一个解一致:Rows = [1,1,1,3], Cols = [1,2,3,2]。


内容的提问来源于stack exchange,提问作者Omar Saleh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:01:13