Steve Hunter did an excellent analysis of the problem and then produced an *extremely* fast version, writen in Python, that he shared with me. I, uh, 'borrowed' some of his analysis and backed it into the last Icon version I posted. The result is so fast that I can't time the "13 coins for $1.10" problem - it runs faster than my timer resolution. However, I can time a "52 coins for $4.40" solution - ~20ms! The previous version takes over 5 seconds. Thanks, Steve!
I've attached the latest (and my last, I promise!) solution. As a rough measure, the previous version made 1913 calls to the genCoins() procedure in the 13/110 problem - this one makes 53. -Steve -- Steve Wampler [EMAIL PROTECTED] The gods that smiled upon your birth are laughing now. -- fortune cookie
global cMap, nMap, min_denom, min_value # Given a monetary amount TARGET in US cents, and a number N of # coins, generates all possible combinations of N US coins that # exactly match TARGET cents. # procedure main(args) start := &time target := integer(args[1]) | 110 nCoins := integer(args[2]) | 13 # Precompute a few constant values # US coin demoninations...and their worth in cents. allCoins := "DFQdnp" cMap := table() cMap["D"] := 100; cMap["F"] := 50; cMap["Q"] := 25 cMap["d"] := 10; cMap["n"] := 5; cMap["p"] := 1 # Worth of the 'next' denomination for each of the above nMap := table() nMap["D"] := 50; nMap["F"] := 25; nMap["Q"] := 10 nMap["d"] := 5; nMap["n"] := 1 # Minimum denomination and its worth min_denom := allCoins[-1] min_value := cMap[min_denom] # Now solve the problem write("Combinations of ",nCoins," US coins to make ",target," cents:") every i := 1 to *allCoins do { coin := allCoins[i] coins := allCoins[i:0] process(genCoins(genDenom(coin,target,nCoins),nCoins,target,coins)) } write(&errout, "Time: ",&time-start) end # Generate solutions. # procedure genCoins(s, i, t, coins) if (i < *s) | (t < 0) then fail cValue := cMap[s[1]]*(*s) if i = *s then return (t = cValue, s) else { t -:= cValue every k := 2 to *coins do { suspend s || genCoins(genDenom(coins[k],t,i-*s),i-*s,t,coins[k:0]) } } end # Generate longer sequences of a given demonination, stop when it # makes sense to stop (too many coins or too much money). # procedure genDenom(c, t, nc) if c == min_denom then return (t=(min_value*nc), repl(c,nc)) value := cMap[c] nValue := nMap[c] max_c := (nc > ((t-(min_value*nc)) / (value-min_value))) | nc min_c := (0 < (t-nValue*nc)/(value-nValue)) | 1 coins := repl(c, min_c-1) suspend (min_c to max_c, coins ||:= c) end # Have a solution, output it. # (Could produce a more human-friendly form here, if desired.) # procedure process(answer) write("\t",answer) end