简体   繁体   中英

Subset sum Prolog

Define a predicate subsetsum(L, Sum, Subl) that takes a list L of numbers, a number Sum, and unifies SubL with a sub sequence of L such that the sum of the numbers in SubL is Sum.

For example

   ?- subsetsum([1,2,5,3,2], 5, SubSet);

   SubSet = [1,2,2];
   SubSet = [2,3]; 
   SubSet = [5]; 
   SubSet = [3,2];

No.

we have

 sum([H1 | [H2 | Tail]], S):-
   sum([[H1+H2]|Tail], S):-
 sum([X], X).

and

  subset([],[]).
  subset([H1|T1], [H1|T2]) :-  // heads are the same
    subset(T1, T2).
  subset([_|Rest], X):
    subset(Rest, X).

If all numbers used are integers and your Prolog processor supports , proceed like this!

:- use_module(library(clpfd)).

z_z_product(A,B,AB) :-
   AB #= A*B.

subsetsum_(Zs, Sum, Bs, [Sum|Vs]) :-
   same_length(Zs, Bs),
   append(Zs, Bs, Vs),
   Bs ins 0..1,
   maplist(z_z_product, Zs, Bs, Xs),
   sum(Xs, #=, Sum).

Sample query:

?- subsetsum_([1,2,5,3,2], 5, Sel, Vs), labeling([], Vs).
   Sel = [0,0,0,1,1], Vs = [5,1,2,5,3,2,0,0,0,1,1]
;  Sel = [0,0,1,0,0], Vs = [5,1,2,5,3,2,0,0,1,0,0]
;  Sel = [0,1,0,1,0], Vs = [5,1,2,5,3,2,0,1,0,1,0]
;  Sel = [1,1,0,0,1], Vs = [5,1,2,5,3,2,1,1,0,0,1]
;  false.

The following clauses should do what you need...

subsetsum(SET, SUM, ANSWER) :-
    % Find a subset
    subset(SET, ANSWER),
    % Check elements of the subset add up to SUM
    sum(ANSWER, SUM).

% sum(LIST, SUM) - sums all numbers in the list
sum([], 0).
sum([X | T], SUM) :-
    sum(T, TAILSUM),
    SUM is TAILSUM + X.

% subset - finds subsets
subset([], []).
subset([E|Tail], [E|NTail]) :-
    subset(Tail, NTail).
subset([_|Tail], NTail) :-
    subset(Tail, NTail).

With we can use the library predicate sum_list/2 together with that subset/2 you already got! Note that I gave subset/2 the better fitting name list_subsequence/2 :

list_subsequence([], []).
list_subsequence([X|Xs], [X|Ys]) :-
   list_subsequence(Xs, Ys).
list_subsequence([_|Xs], Ys) :-
   list_subsequence(Xs, Ys).

subsetsum(List, Sum, Sub) :-
   list_subsequence(List, Sub),
   sum_list(Sub, Sum).

Here is the sample query that you gave:

?- subsetsum([1,2,5,3,2], 5, Xs).
   Xs = [1,2,2]
;  Xs = [2,3]
;  Xs = [5]
;  Xs = [3,2]
;  false.

OK! Let's run another query with both integers and floats... does that work, too?

?- subsetsum([1,,5,3,2], , Xs).
   Xs = [1,,2]
;  Xs = [,3]
;  false.

Looks alright to me!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM