【问题标题】:From 8-Queens solution to more generic n-Queens solution in Prolog从 8-Queens 解决方案到 Prolog 中更通用的 n-Queens 解决方案
【发布时间】:2013-03-28 05:20:15
【问题描述】:

我正在为大学考试学习 Prolog,但我在以下练习中遇到了一些问题。

我有以下 8 皇后问题的经典解决方案(这对我来说不是问题),修改这个解决方案我必须为处理可变数量皇后的更通用的 n 皇后问题创建一个新的解决方案.

solution([]).

solution([X/Y|Others]) :- solution(Others),
                          member(Y,[1,2,3,4,5,6,7,8]),
                          noattack(X/Y, Others).

noattack(_,[]).

noattack(X/Y, [X1/Y1 | Others]) :-
                      Y =\= Y1,       % Q e Q1 sono su righe diverse
                      % Q e Q1 sono su diagonali diverse:
                      Y1-Y =\= X1-X,
                      Y1-Y =\= X-X1,
                      % Q non attacca regine nella sottolista Others:
                      noattack( X/Y, Others).

% TEMPLATE DELLE SOLUZIONI: c'è una regina su ogni colonna:
template([1/Y1,2/Y2,3/Y3,4/Y4,5/Y5,6/Y6,7/Y7,8/Y8]).

好的,这个程序看起来很简单:我有一个女王名单,他们不能互相攻击。

如果女王列表为空,则女王不可能攻击列表中的另一个女王,因此空列表是问题的解决方案(它是解决方案的基本情况)强>

*如果皇后列表不为空,我可以将其划分为 [X/Y|Others],其中 X/Y 表示列表中第一个皇后在棋盘上的位置 *(位置是由一对 (X,Y) 表示的,其中 X 是列,Y 是行)

因此,如果以下关系为真,则列表 [X/Y|Others] 是问题的解决方案是正确的:

  1. 子列表 Others 本身就是一个解决方案(Others 不包含攻击列表中其他女王的女王)

  2. Y属于1到8之间的整数值(因为我有8行)

  3. 列表的第一个女王不要攻击子列表Others中的其他女王

然后定义 noattack 关系,指定我何时可以说一个蜂后确实不攻击另一个蜂后(这很简单:它们不能保持不变行,在同一列,在同一对角线)

最后我有一个解决方案模板,可以简化我的生活,将 X 值限制在 1 到 8 之间(因为我知道 2 个皇后不能留在同一列上......所以每个解决方案中的皇后与所有其他皇后保持在不同的列上)

所以我认为最大的问题在于我指定列数的那一行:

member(Y,[1,2,3,4,5,6,7,8])

在我定义解决方案模板的那一行:

template([1/Y1,2/Y2,3/Y3,4/Y4,5/Y5,6/Y6,7/Y7,8/Y8]).

我不知道如何扩展之前的解决方案来处理可变数量的皇后。

【问题讨论】:

    标签: prolog n-queens


    【解决方案1】:

    似乎很容易,传递大小:

    solution(_, []).
    solution(N, [X/Y|Others]) :-
        solution(N, Others),
        between(1, N, Y),
        noattack(X/Y, Others).
    
    noattack(_,[]).
    noattack(X/Y, [X1/Y1 | Others]) :-
        Y =\= Y1,       % Q e Q1 sono su righe diverse
        Y1-Y =\= X1-X,  % Q e Q1 sono su diagonali diverse
        Y1-Y =\= X-X1,
        noattack( X/Y, Others). % Q non attacca regine nella sottolista Others
    
    % TEMPLATE DELLE SOLUZIONI: c'è una regina su ogni colonna:
    template(N, L) :-
        findall(I/_, between(1,N,I), L).
    

    测试:

    ?- N=6, template(N, L), solution(N, L).
    N = 6,
    L = [1/5, 2/3, 3/1, 4/6, 5/4, 6/2] ;
    N = 6,
    L = [1/4, 2/1, 3/5, 4/2, 5/6, 6/3] ;
    N = 6,
    L = [1/3, 2/6, 3/2, 4/5, 5/1, 6/4] ;
    N = 6,
    L = [1/2, 2/4, 3/6, 4/1, 5/3, 6/5] ;
    false.
    

    (我应该画出来说好不好……)

    【讨论】:

    • Tnx 这么多。感谢您的帮助和您的时间。关于它的工作原理,我只有两点:
    • 1) 要成为真的 solution(N, [X/Y|Others]) (由 N 个皇后组成的列表 [X/Y|Others] 是一个解决方案),您必须添加确实如此:在(1,N,Y)之间代替成员(Y,[1,2,3,4,5,6,7,8])。这一天 Y(列数)将 >1 且
    • 2) 第二个疑问与您如何在 N 皇后案例中构建解决方案模板有关......我认为它的含义类似于我有一个列表的保持模板,例如: [1/Y1,2/Y2,....,8/Y8]。但在这种情况下,我不能有一个“静态”列表,但必须用可变数量的位置(N 个位置)实例化该列表。所以你这样做:模板(N,L):- findall(I / _,介于(1,N,I),L)。但究竟是什么意思?我认为 findall 以动态方式创建列表...列表由一对 (X,Y) 组成,其中 X 表示行索引,Y 表示列索引。
    • 好的...就像在旧的 8 皇后示例中一样,我有一个模板列表(由 findall 创建?对吗?)每个皇后都在不同的行上,所以我有每个皇后都在位置 I/_ ,其中 I 是从 1 到 N 的数字(所以如果 N=3 我有一个模板列表,如 [1/_,2/,3/_]。疑问是:为什么 Y 值是 _ 而不是Y?,第二个疑惑是:L rappresent the List created by findall?Tnx so much
    • 1) 在 Prolog 中我们有 relations,碰巧你写的 member/2 和 between/3 都表示相同的关系。可以使用numlist(1, N, L), member(Y, L),但当我知道时,我更喜欢更简单的解决方案。 2)导致 findall 输出列表的每个_ 都是独立的,与 Y1、Y2 等完全一样,它们的基本目的是通过搜索来评估“空闲”插槽。所以 findall/3 很方便。这是 Prolog 的“列表理解”......
    猜你喜欢
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多