Subset sum problem: Difference between revisions
Content added Content deleted
m (→{{header|REXX}}: added/changed comments and whitespace, used a template for the outputs.) |
|||
Line 1,482: | Line 1,482: | ||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
This REXX solution isn't limited to integers for the weights. This isn't a brute force solution. |
This REXX solution isn't limited to integers for the weights. This isn't a brute force solution. |
||
<br><br>While optimizing the original program, it was found that sorting the names by weight could yield a vastly |
|||
While optimizing the original program, it was found that sorting the names by weight could yield a vastly |
|||
<br>improved algorithm (by an order of magnitude), so the extra code to sort the list was included, as well as |
<br>improved algorithm (by an order of magnitude), so the extra code to sort the list was included, as well as |
||
<br>another sort to show the solutions in alphabetical order. Support was also added to allow specification of |
<br>another sort to show the solutions in alphabetical order. Support was also added to allow specification of |
||
<br>which "chunk" to search for solutions (that is, out of the 31 names, take a "chunk" at a time). |
<br>which "chunk" to search for solutions (that is, out of the 31 names, take a "chunk" at a time). |
||
<br><br>Showing of the timing (elapsed time) was also added, as well as "que pasa" informational messages. The |
|||
<br>sum (which is zero for this task) can be any number, and can be specifiable on the command line. |
|||
<lang rexx>/*REXX pgm finds some non-null subsets of a weighted list whose sum=zero*/ |
|||
parse arg target stopAt chunkette . /*get args from the command line*/ |
|||
if target==''|target==',' then target=0 /*TARGET given? No, use default*/ |
|||
if stopAt==''|stopAt==',' then stopAt=1 /*Max solutions? " " " */ |
|||
Showing of the timing (elapsed time) was also added, as well as "que pasa" informational messages. The |
|||
zzz = 'alliance -624 archbishop -915 balm 397' , |
|||
<br>sum (which is zero for this task) can be any number, and can be specifiable on the command line. |
|||
'bonnet 452 brute 870 centipede -658' , |
|||
<lang rexx>/*REXX program finds some non─null subsets of a weighted list whose sum eqals zero.*/ |
|||
'cobol 362 covariate 590 departure 952' , |
|||
parse arg target stopAt chunkette . /*option optional arguments from the CL*/ |
|||
'deploy 44 diophantine 645 efferent 54' , |
|||
if target=='' | target=="," then target=0 /*Not specified? Then use the default.*/ |
|||
'elysee -326 eradicate 376 escritoire 856' , |
|||
if stopAt=='' | stopAt=="," then stopAt=1 /* " " " " " " */ |
|||
y=0 |
|||
'flatworm 503 gestapo 915 infra -847' , |
|||
zzz= 'alliance -624 archbishop -915 balm 397' , |
|||
'bonnet 452 brute 870 centipede -658' , |
|||
'cobol 362 covariate 590 departure 952' , |
|||
'deploy 44 diophantine 645 efferent 54' , |
|||
'vein 813' |
|||
'elysee -326 eradicate 376 escritoire 856' , |
|||
'exorcism -983 fiat 170 filmy -874' , |
|||
'flatworm 503 gestapo 915 infra -847' , |
|||
'isis -982 lindholm 999 markham 475' , |
|||
'mincemeat -880 moresby 756 mycenae 183' , |
|||
'plugging -266 smokescreen 423 speakeasy -745' , |
|||
'vein 813' |
|||
@.=0 |
|||
do N=1 until zzz='' /*construct an array from the ZZZ list.*/ |
|||
parse var zzz @.N #.N zzz /*pick from the list like a nose. */ |
|||
end /*N*/ |
|||
call eSort N /*sort the names with weights. */ |
|||
call tellZ 'sorted' /*display the sorted list. */ |
|||
chunkStart=1 /*the default place to start. */ |
|||
chunkEnd =N /* " " " " end. */ |
|||
if chunkette\=='' then do /*solutions just for a chunkette. */ |
|||
chunkStart= chunkette |
|||
chunkEnd = chunkette |
|||
end |
|||
call time 'Reset' /*reset the REXX elapsed time. */ |
|||
??=0 /*the number of solutions (so far). */ |
|||
do chunk=chunkStart to chunkEnd /*traipse through the items. */ |
|||
call tello center(' doing chunk:' chunk" ", 79, '─') |
|||
call combN N, chunk /*N items, a CHUNK at a time. */ |
|||
_=??; if _==0 then _= 'No' /*Englishise for a zero count. */ |
|||
call tello _ 'solution's(??) "found so far and took", |
|||
format( time('Elapsed'), , 2) "seconds so far.", . |
|||
end /*chunk*/ |
|||
if ??==0 then ??= 'no' /*Englishise the solutions number. */ |
|||
call tello 'Found' ?? "subset"s(??) 'whose summed weight's(??) "=" target |
|||
exit /*stick a fork in it, we're all done. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
call esort N /*sort the names with weights.*/ |
|||
combN: procedure expose @. #. ?? stopAt target; parse arg x,y; !.=0 |
|||
base= x+1; bbase= base-y /*!.n are the combination digits. */ |
|||
do n=1 for y; !.n=n /*construct the first combination. */ |
|||
end /*n*/ |
|||
ym= y-1 |
|||
chunkStart=chunkette |
|||
do j=1; _=!.1; s=#._ /*obtain the first digit and the sum. */ |
|||
if s>target then leave /*Is 1st dig>target? Then we're done.*/ |
|||
do k=2 for ym; _=!.k; s=s + #._ /*Σ the weights; is sum > target ? */ |
|||
if s>target then do; if .combUp(k-1) then return; iterate j; end |
|||
end /*k*/ |
|||
if s==target then call telly /*have we found a pot of gold? */ |
|||
!.y= !.y + 1; if !.y==base then if .combUp(ym) then leave /*bump digit.*/ |
|||
call tello center(' doing chunk:' chunk" ",79,'─') |
|||
end /*j*/ |
|||
return /*done with this combination set. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
call tello _ 'solution's(??) "found so far and took", |
|||
.combUp: procedure expose !. y bbase; parse arg d; if d==0 then return 1 |
|||
format(time('Elapsed'),,2) 'seconds so far.',. |
|||
p=!.d; do u=d to y; !.u=p + 1 /*add one to digit we're pointing at. */ |
|||
end /*chunk*/ |
|||
if !.u >= bbase+u then return .combUp(u-1) |
|||
p=!.u /*P will be used for the next digt. */ |
|||
end /*u*/ |
|||
call tello 'Found' ?? "subset"s(??) 'whose summed weight's(??) "=" target |
|||
return 0 /*go back and sum this combination. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
/*──────────────────────────────────COMBN subroutine────────────────────*/ |
|||
eSort: procedure expose #. @. $.; parse arg N,$; h=N |
|||
do while h>1; h=h%2 |
|||
do i=1 for N-h; j=i; k=h+i |
|||
if $==. then do while $.k<$.j; parse value $.j $.k with $.k $.j |
|||
if h>=j then leave; j=j-h; k=k-h |
|||
end /*while $.k<$.j*/ |
|||
else do while #.k<#.j; parse value @.j @.k #.j #.k with @.k @.j #.k #.j |
|||
if h>=j then leave; j=j-h; k=k-h |
|||
end /*while #.k<#.j*/ |
|||
end /*i*/ |
|||
if s>target then do; if .combUp(k-1) then return; iterate j; end |
|||
end /* |
end /*while h>1*/ |
||
return |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
if s==target then call telly /*have we found a pot of gold? */ |
|||
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*simple pluralizer*/ |
|||
tello: parse arg _,e; if e==. then say; say _; call lineout 'SUBSET.'y, _; return |
|||
end /*j*/ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
return /*done with this combination set.*/ |
|||
telly: ??=??+1; nameL= /*start with a "null" name list. */ |
|||
do gi=1 for y; ggg= !.gi /*build duplicate array (to be sorted).*/ |
|||
.combUp: procedure expose !. y bbase; parse arg d; if d==0 then return 1 |
|||
$.gi= @.ggg /*transform from index ──► a name. */ |
|||
end /*gi*/ /*build duplicate array (to be sorted).*/ |
|||
if !.u>=bbase+u then return .combUp(u-1) |
|||
call eSort y, . /*sort the names alphabetically. */ |
|||
do gs=1 for y; nameL=nameL $.gs /*build a list of names whose sum = 0 */ |
|||
end /*gs*/ /*the list of names could be sorted. */ |
|||
call tello '['y" name"s(y)']' space(nameL) |
|||
/*──────────────────────────────────ESORT subroutine────────────────────*/ |
|||
if ??<stopAt | stopAt==0 then return /*see if we reached a (or the) limit.*/ |
|||
esort: procedure expose #. @. $.; parse arg N,$; h=N |
|||
call tello 'Stopped after finding ' ?? " subset"s(??)'.', . |
|||
exit /*a short─timer, we should quit then. */ |
|||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
|||
if $==. then do while $.k<$.j; parse value $.j $.k with $.k $.j |
|||
tellz: do j=1 for N /*show a list of names and weights. */ |
|||
call tello right('['j']', 30) right(@.j, 11) right(#.j, 5) |
|||
end /*j*/ |
|||
call tello |
|||
if h>=j then leave; j=j-h; k=k-h |
|||
call tello 'There are ' N " entries in the (above)" arg(1) 'table.' |
|||
call tello; return</lang> |
|||
end /*while h>1*/ |
|||
return |
|||
/*──────────────────────────────────one─liner subroutines─────────────────────*/ |
|||
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*plural*/ |
|||
tello: parse arg _,e; if e==. then say; say _; call lineout 'SUBSET.'y,_; return |
|||
/*──────────────────────────────────TELLY subroutine────────────────────*/ |
|||
telly: ??=??+1; nameL= /*start with a "null" name list. */ |
|||
do gi=1 for y; ggg=!.gi /*build dup array (to be sorted).*/ |
|||
$.gi=@.ggg /*transform from index──► a name.*/ |
|||
end /*gi*/ /*build dup array (to be sorted).*/ |
|||
call eSort y,. /*sort the names alphabetically. */ |
|||
do gs=1 for y; nameL=nameL $.gs /*build list of names whose sum=0*/ |
|||
end /*gs*/ /*list of names could be sorted */ |
|||
call tello '['y" name"s(y)']' space(nameL) |
|||
if ??<stopAt | stopAt==0 then return /*see if we reached a (the) limit*/ |
|||
call tello 'Stopped after finding ' ?? " subset"s(??)'.',. |
|||
exit /*a short─timer, we have to quit.*/ |
|||
/*──────────────────────────────────TELLZ subroutine────────────────────*/ |
|||
tellz: do j=1 for N /*show list of names and weights.*/ |
|||
call tello right('['j']',30) right(@.j,11) right(#.j,5) |
|||
end /*j*/ |
|||
call tello |
|||
call tello 'There are ' N " entries in the (above)" arg(1) 'table.' |
|||
call tello; return</lang> |
|||
Output note: this program also writes the displayed output to file(s): SUBSET.nnn |
Output note: this program also writes the displayed output to file(s): SUBSET.nnn |
||
<br> ──────── where nnn is the ''chunk'' number. |
<br> ──────── where nnn is the ''chunk'' number. |
||
<br> |
|||
{{ |
{{out|output|text= when using the input of: <tt> 0 12 </tt>}} |
||
(The above arguments set the target sum to zero and limits finding of a dozen solutions.) |
|||
(The above arguments set the target sum to zero, and limits the finding of a dozen solutions.) |
|||
<pre style="height:90ex"> |
<pre style="height:90ex"> |
||
[1] exorcism -983 |
[1] exorcism -983 |