【问题标题】:Prolog: Arrangements of k elements with sum of elements SProlog:具有元素总和 S 的 k 个元素的排列
【发布时间】:2016-02-12 08:58:35
【问题描述】:

我正在尝试在 Prolog 中计算 K 元素的排列,其中它们的元素之和等于给定的 S。所以,我知道可以通过找到组合然后排列它们来计算排列。我知道如何计算 K 元素的组合,例如:

comb([E|_], 1, [E]).
comb([_|T], K, R) :-
   comb(T, K, R).
comb([H|T], K, [H|R]) :-
   K > 1,
   K1 is K-1,
   comb(T, K1, R).

列表的排列,具有元素之和等于给定 S 的属性,我知道这样计算:

insert(E, L, [E|L]).
insert(E, [H|T], [H|R]) :-
   insert(E, T, R).

perm([], []).
perm([H|T], P) :-
   perm(T, R),
   insert(H, R, P).

sumList([], 0).
sumList([H], H) :-
   number(H).
sumList([H|Tail], R1) :-
   sumList(Tail, R),
   R1 is R+H.

perms(L, S, R) :-
   perm(L, R),
   sumList(R, S1),
   S = S1.

allPerms(L, LP) :-
   findall(R, perms(L,R), LP).

问题是我不知道如何组合它们,以便获得K 元素的排列,使元素的总和等于给定的S。任何帮助将不胜感激。

【问题讨论】:

  • 您是在使用 any 数字,还是仅使用整数?
  • 您使用的是哪个 Prolog 处理器? SICStus? SWI?

标签: list prolog combinations permutation clpfd


【解决方案1】:

使用

:- use_module(library(clpfd))。

使用 SWI-Prolog 7.3.16 我们查询:

?- length(Zs,4), Zs ins 1..4, sum(Zs,#=,7), labeling([],Zs)。 Zs = [1,1,1,4] ; Zs = [1,1,2,3] ; Zs = [1,1,3,2] ; Zs = [1,1,4,1] ; Zs = [1,2,1,3] ; Zs = [1,2,2,2] ; Zs = [1,2,3,1] ; Zs = [1,3,1,2] ; Zs = [1,3,2,1] ; Zs = [1,4,1,1] ; Zs = [2,1,1,3] ; Zs = [2,1,2,2] ; Zs = [2,1,3,1] ; Zs = [2,2,1,2] ; Zs = [2,2,2,1] ; Zs = [2,3,1,1] ; Zs = [3,1,1,2] ; Zs = [3,1,2,1] ; Zs = [3,2,1,1] ; Zs = [4,1,1,1]。

要消除“冗余模排列”解决方案,请使用chain/2

?- length(Zs,4), Zs ins 1..4, chain(Zs,#=, sum(Zs,#=,7), labeling([],Zs )。 Zs = [1,1,1,4] ; Zs = [1,1,2,3] ; Zs = [1,2,2,2] ;错误的。

【讨论】:

  • 我尝试这样做 qst 但我有这个结果 (length=3,Sum3) :List = [_A,_B,_C], _A in inf..sup, _B in inf..sup, _C in inf..sup ? 我如何从inf..sup 恢复值
  • @AnsPiter 尝试在Sum3 中提供值而不是变量?套用你的代码,你基本上是在说,“给我三样东西,加起来就是任何东西。”中电回来说,“这里有三样有价值的东西。”这就是为什么 repeat 给了Zs ins 1..4sum(Zs, #=, 7) 来约束解空间。
  • @AnsPiter。丹尼尔是对的。如果您使用 SICStus,请执行 assert(clpfd:full_answer) 以确保 prolog-toplevel 显示剩余约束 — 这样您就不会觉得证明不完整!
  • @repeat,@Daniel Lyons,谢谢
【解决方案2】:

我使用 SWI-Prolog。 你可以这样写

:- use_module(library(lambda)).

arrangement(K, S, L) :-
    % we have a list of K numbers
    length(L, K),
    % these numbers are between 1 (or 0) and S
    maplist(between(1, S), L),
    % the sum of these numbers is S
    foldl(\X^Y^Z^(Z is X+Y), L, 0, S).

结果

 ?- arrangement(5, 10, L).
L = [1, 1, 1, 1, 6] ;
L = [1, 1, 1, 2, 5] ;
L = [1, 1, 1, 3, 4] ;
L = [1, 1, 1, 4, 3] .

您也可以使用 CLP(FD) 库。

@repeat的评论后编辑。

【讨论】:

  • when(ground(L), ...) 是干什么用的?哪些用例可以从中受益?
  • @repeat 你说的很对,没必要。
【解决方案3】:

此响应类似于 @repeat

的响应

以下谓词是使用 SICStus 4.3.2 工具实现的

简单修改gen_list(+,+,?)

编辑代码

gen_list(Length,Sum,List) :-    length(List,Length), 
                                domain(List,0,Sum), 
                                sum(List,#=,Sum), 
                                labeling([],List),

                                % to avoid duplicate results
                                ordered(List).

测试

| ?- gen_list(4,7,L).
L = [0,0,0,7] ? ;
L = [0,0,1,6] ? ;
L = [0,0,2,5] ? ;
L = [0,0,3,4] ? ;
L = [0,1,1,5] ? ;
L = [0,1,2,4] ? ;
L = [0,1,3,3] ? ;
L = [0,2,2,3] ? ;
L = [1,1,1,4] ? ;
L = [1,1,2,3] ? ;
L = [1,2,2,2] ? ;
no

【讨论】:

  • 保持简单!使用 SICStus Prolog 4.3.2,充分利用库谓词 domain/3sum/3?- length(Zs,4), domain(Zs,1,4), sum(Zs,#=,7), labeling([],Zs).
  • 我没明白。 “也许无法避免重复的结果”是什么意思?你试过ordered/1(上面的链接)吗?
  • 好的!但是为什么你写labeling([],List), ordered(List), Res = List ; false 而不是ordered(List), labeling([],List) 并始终使用List?一般来说,最好在标记之前发布约束。
  • 更好,是的。但是为什么要把labeling/2 目标放在ordered/1 目标之前呢?这里有一些很好的材料可以解释为什么最后做标签是正确的:github.com/triska/clpfd/blob/master/clpfd.pdf
  • 不要只选择任何实现!坚持这个答案中提出的那个:stackoverflow.com/a/31094645/4609915
【解决方案4】:

我认为排列可能与您的问题无关。由于求和运算是可交换的,因此元素的顺序实际上应该是无关紧要的。所以,经过这次修正

sumList([], 0).
%sumList([H], H) :-
%   number(H).
sumList([H|Tail], R1) :-
   sumList(Tail, R),
   R1 is R+H.

你可以只使用你的谓词

'arrangements of K elements'(Elements, K, Sum, Arrangement) :-
    comb(Elements, K, Arrangement),
    sumList(Arrangement, Sum).

测试:

'arrangements of K elements'([1,2,3,4,5,6],3,11,A).
A = [2, 4, 5] ;
A = [2, 3, 6] ;
A = [1, 4, 6] ;
false.

如果需要,您已经知道如何使用 findall/3 一次获取所有列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多