Prolog,删除生成中的重复结果

时间:2010-12-12 10:35:16

标签: prolog

我写了一个prolog程序,它在二维表中生成元素的所有可能位置。给出了元素的数量和表格大小。

我的代码是:

geni(Min, Min, Max) :- Min =< Max.
geni(Min, X, Max) :- Max >= Min, MinInc is Min+1, geni(MinInc, X, Max).
generate(_, 0, []) :- !.
generate(TSize, N, [X|Tail]) :- NDec is N-1, generate(TSize,NDec, Tail),
                                X=k(X1,Y1), geni(1,X1,TSize), geni(1,Y1,TSize), 
                                not(member(X, Tail)).

TSize是表的大小,N是元素的数量,最后一个是结果) 谓词geni在区间X中生成数字[A;B]

示例(2x2表中的2个元素):

?- generate(2, 2, R).
R = [k(1, 1), k(1, 2)] ;
R = [k(1, 1), k(2, 1)] ;
R = [k(1, 1), k(2, 2)] ;
R = [k(1, 2), k(1, 1)] ;
R = [k(1, 2), k(2, 1)] ;
R = [k(1, 2), k(2, 2)] ;
R = [k(2, 1), k(1, 1)] ;
R = [k(2, 1), k(1, 2)] ;
R = [k(2, 1), k(2, 2)] ;
R = [k(2, 2), k(1, 1)] ;
R = [k(2, 2), k(1, 2)] ;
R = [k(2, 2), k(2, 1)] ;
false.

我的桌子是棋盘,元素是骑士。在这种情况下,所有元素都是相同的,但我的程序“认为”是不同的。 如何避免同等的结果?像这样:

R = [k(1, 1), k(1, 2)] ;
R = [k(1, 2), k(1, 1)] ;

1 个答案:

答案 0 :(得分:4)

目前,您正在使用not(member(...))来确保结果不重复。为了避免获得结果的所有排列,您只需确保结果中的元素是有序的。

第1步是定义一个订单,例如:

% A knight 1 is "bigger" than knight 2
% if the X-value is bigger or X is equal and Y is bigger
is_bigger(k(X1, Y1), k(X2, Y2)) :-
    X1 > X2; (X1 = X2, Y1 > Y2).

现在你必须确保你想要添加到列表中的元素比所有其他元素“更大”。

geni(Min, X, Max) :- between(Min, Max, X).
generate(_, 0, []) :- !.
generate(TSize, N, [X|Tail]) :- X=k(X1,Y1),  NDec is N-1,
                            generate(TSize,NDec, Tail),
                            geni(1,X1,TSize),
                            geni(1,Y1,TSize),
                            maplist(is_bigger(X), Tail).

我使用内置谓词maplist来测试列表的所有元素。弗罗姆这个例子应该清楚它是如何运作的。

如果您想要撤销订单,请改为使用“更低”。

?- generate(2, 2, T).
T = [k(1, 2), k(1, 1)] ;
T = [k(2, 1), k(1, 1)] ;
T = [k(2, 2), k(1, 1)] ;
T = [k(2, 1), k(1, 2)] ;
T = [k(2, 2), k(1, 2)] ;
T = [k(2, 2), k(2, 1)] ;
false.