Prolog:具有元素S总和的k个元素的排列

时间:2016-02-12 08:58:35

标签: list prolog combinations permutation clpfd

我正在尝试计算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。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:3)

我使用SWI-Prolog。 你可以写那个

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Server><Service name=\"Catalina\">" +
                "<Engine name=\"Catalina\"></Engine>" +
                "<Engine name=\"Catalina\"></Engine>" +
                "<Engine name=\"Catalina\"></Engine>" +
                "</Service></Server>";

            XDocument doc = XDocument.Parse(xml);

            foreach(XElement engine in doc.Descendants("Engine"))
            {
                object[] newNode =  { new XElement("Host", new XAttribute("name", "localhost")), new XElement("Value")};
                engine.Add(newNode);
            }

        }
    }
}

结果

:- 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).

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

@repeat 的评论后编辑。

答案 1 :(得分:3)

使用

:- 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]
;  false.

答案 2 :(得分:1)

此响应类似于 @repeat

的响应

预测以下是使用 SICStus 4.3.2 工具

实现的

简单修改next_case_split(bool_var & next, lbool & phase)

修改代码

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

答案 3 :(得分:0)

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

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立即获取所有列表。