我有一个谓词来生成数字列表,
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 < Y
和S = 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,直到达到限制并继续递归执行此操作。这应确保创建所有可能的对。
答案 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).
通过向上计数而不是向下计数,我可以保持列表的正向顺序并保持尾递归,而无需使用辅助列表。我受X
和Sum
限制,让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
收集它们。该解决方案可轻松扩展,以支持更多的加数。