生成符合特定条件的数字列表

时间:2015-03-16 17:32:48

标签: prolog

我有一个谓词来生成数字列表,

generate_numbers(0,[]).
generate_numbers(N,[Head|Tail]):-
                    N > 0,                      
                    Head is N,                  
                    N1 is N-1,                  
                    generate_numbers(N1,Tail).  

我正在尝试修改它,以便生成数字X和Y达到限制。条件是1 < X < YS = X + Y以及S < 100

我正在努力弄清楚如何做到这一点,我已经尝试过,但它远远不够正确。

generate_numbers(1,[]).
generate_numbers(X,[[Head,Y,S]|Tail]):-
                    X > 1,                      
                    Head is X,
                    Y is X+1,
                    S is X + Y,
                    X1 is X-1,                  
                    generate_numbers(X1,Tail).

我确实检查了S > 100,但这使得代码无法正常工作。

我所追求的输出将与[1,2,3], [2,4,6], [3,9,12], [20,25,45]一致。显然,这只是一些例子,实际上将有1000个。

我认为我可能需要两次递归。因此,向X添加1,然后继续向Y添加1直到达到限制,向X添加1并再次向Y添加1,直到达到限制并继续递归执行此操作。这应确保创建所有可能的对。

1 个答案:

答案 0 :(得分:1)

有几种方法可以解决这个问题。蛮力方式是具有第二层基础案例,以在求和中迭代两个加数之一。此解决方案将首先按总和的顺序提供列表,然后按X的值:

提供
gen_numbers(MaxSum, Result) :-
    MaxSum > 1,
    gen_numbers(2, MaxSum, 1, Result).

gen_numbers(Sum, Sum, Sum, []).            % 'Sum' has reached max value
gen_numbers(Sum, MaxSum, Sum, Result) :-   % 'X' has reached max value
    Sum < MaxSum,
    Sum1 is Sum + 1,
    gen_numbers(Sum1, MaxSum, 1, Result).
gen_numbers(Sum, MaxSum, X, [[X, Y, Sum]|Result]) :-
    Sum =< MaxSum,
    X < Sum,
    Y is Sum - X,
    X1 is X + 1,
    gen_numbers(Sum, MaxSum, X1, Result).

通过向上计数而不是向下计数,我可以保持列表的正向顺序并保持尾递归,而无需使用辅助列表。我受XSum限制,让Y变化。我认为你可以根据你想要的任何变量轻松修改它。

更简洁的方法是使用CLPFD库并将条件指定为约束:

:- use_module(library(clpfd)).

summation(Sum, [X, Y, S]) :-
    [X, Y] ins 1..Sum,
    sum([X, Y], #=<, Sum),
    label([X, Y]),
    S is X + Y.

gen_numbers(MaxSum, Result) :-
    findall([X, Y, S], summation(MaxSum, [X, Y, S]), Result).

此处,summation/2一次显示每个解决方案中的一个,findall/3收集它们。该解决方案可轻松扩展,以支持更多的加数。