如何创建加起来等于特定数字的数字列表
我需要一些帮助,在 Prolog 中编写一个谓词,给定一个数字作为输入,返回一个列表列表,其中的数字相加。
让我们调用谓词 addUpList/2,它应该像这样工作:
?- addUpList(3,P).
P = [[1,2], [2,1], [1,1,1]]. % expected result
我很难弄清楚这一点,我开始认为这是不可能的。有什么想法吗?提前致谢。
I need some help writing a predicate in Prolog that, given a number as input, returns a list of lists with numbers that add up to it.
Let's call the predicate addUpList/2, it should work like this:
?- addUpList(3,P).
P = [[1,2], [2,1], [1,1,1]]. % expected result
I'm having so much trouble figuring this out I'm beginning to think it's impossible. Any ideas? Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
试试这个:
让我知道我得到的分数。 :-)
Try this:
Let me know what marks I get. :-)
规则
num_split/2
生成将数字拆分为列表的方法,其中第一个元素X
是1
和之间的任意数字N
和列表的其余部分是NX
的拆分。为了获得所有此类拆分,只需对
num_split/2
调用findall/3
即可。用法示例:
另请参阅@hardmath 的帖子,它给出了相同的答案,但有更多的解释。
The rule
num_split/2
generates ways of splitting a number into a list, where the first elementX
is any number between1
andN
and the rest of the list is a split ofN-X
.In order to get all such splits, just call
findall/3
onnum_split/2
.Usage example:
See also the post by @hardmath which gives the same answer with a bit more explanation.
问题中给出的示例表明需要任何正整数 N ≤ 10 的组合(有序分区)。但请注意,N=3 的解决方案 [3] 似乎已被省略/忽略。 N 的组合数是 2^(N-1),所以 N =10 给出了一个很长的列表,但并不是一个难以管理的列表。
还希望将所有此类解决方案收集到一个列表中,这是在我们编写生成它们的谓词
composition/2
后findall/3
可以通用执行的操作。这个想法是选择第一个被加数(1 到 N 之间的任何值),从总数中减去它并递归(当总数达到零时以空列表停止)。 SWI-Prolog 提供了一个谓词
Between/3 可以生成那些可能的第一个被加数,还有 Amzi! Prolog 提供了类似的谓词
for/4
。为了可移植性,我们在这里编写自己的版本。给定上述经过编译或解释的 Prolog 源代码,可以通过以下方式获得所有解决方案的列表:
当然,您的特定应用程序可能需要对此类解决方案列表进行某种安排或省略单例列表,但这由于问题目前的措辞尚不清楚。
The example given in the Question suggests that compositions (ordered partitions) of any positive integer N ≤ 10 are wanted. Note however that the solution [3] for N=3 seems to have been omitted/overlooked. The number of compositions of N is 2^(N-1), so N=10 gives a long list but not an unmanageable one.
It is also desired to collect all such solutions into a list, something that
findall/3
can do generically after we write a predicatecomposition/2
that generates them.The idea is to pick the first summand, anything between 1 and N, subtract it from the total and recurse (stopping with an empty list when the total reaches zero). SWI-Prolog provides a predicate
between/3
that can generate those possible first summands, and Amzi! Prolog provides a similar predicatefor/4
. For the sake of portability we write our own version here.Given the above Prolog source code, compiled or interpreted, a list of all solutions can be had in this way:
Of course some arrangement of such a list of solutions or the omission of the singleton list might be required for your specific application, but this isn't clear as the Question is currently worded.
这个问题已经有很多很好的答案,但这里有另一个解决方案供您考虑。该程序与其他程序的不同之处在于它非常高效,并生成列表的非冗余解决方案,这些列表被假定表示集合加起来达到指定数字的整数集。
您可以通过以下方式实现
addUpList/2
:这应该为您提供以下行为:
请注意,列表包含一个
2
和两个1
s 在此结果集中仅出现一次;这是因为gen/4
计算加起来达到指定数字的唯一整数集。There are plenty of great answers to this question already, but here is another solution to this problem for you to consider. This program differs from the others in that it is very efficient, and generates non-redundant solutions of lists which are assumed to represent sets of integers which add up to the specified number.
Your implementation of
addUpList/2
can be achieved by:Which should give you the following behaviour:
Note that the list containing one
2
and two1
s only appears once in this result set; this is becausegen/4
computes unique sets of integers which add up to the specified number.这个答案介于两者之间
@Kaarel 的回答 和
@sharky 的“高效”答案。
就像@sharky 的代码一样,我们在相邻列表项之间施加排序关系来限制解决方案空间的大小——知道如何在需要时对其进行膨胀。因此 @sharky 的
break_down/2
和gen/2
的解集是相等的(不考虑列表反转)。至于性能,请考虑:
This answer is somewhere between
@Kaarel's answer and
@sharky's "efficient" answer.
Like @sharky's code, we impose an ordering relation between adjacent list items to restrict the size of the solution space---knowing how to inflate it if we ever need to. So the solution sets of
break_down/2
andgen/2
by @sharky are equal (disregarding list reversal).And as for performance, consider: