2010-12-12 113 views
1

我写了一个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在间隔[A;B]生成数X

实施例(在2×2表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)] ; 

回答

4

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

第一步是定义一个订单,即是这样的:

% 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测试列表中的所有元素。 Frome的例子应该清楚它是如何工作的。

如果您想颠倒顺序,请改为实施“较低”。

?- 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.