我正在尝试计算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
。任何帮助将不胜感激。
答案 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)
使用clpfd!
:- 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立即获取所有列表。