diff --git a/SICP/exercise_1_14.janet b/SICP/exercise_1_14.janet new file mode 100644 index 0000000..f0fe5c9 --- /dev/null +++ b/SICP/exercise_1_14.janet @@ -0,0 +1,140 @@ +# the number of ways to change amount a using n kinds of coins: + +# the number of ways to change amount a using all but the first +# kind of coin + +# + + +# the number of ways to change a - d using all n kinds of coins, +# where d is the denomination of the first kind of coin. + +# c(a, [n = list of coins]) = c(a, n[:1]) + c(a-n[0], n) + +# using the following base rules: + +# if a = 0, result = 1 +# if a < 0, result = 0 +# if n = 0, result = 0 + +(defn first-denomination [kinds-of-coins] + (cond + (= kinds-of-coins 1) 1 + (= kinds-of-coins 2) 5 + (= kinds-of-coins 3) 10 + (= kinds-of-coins 4) 25 + (= kinds-of-coins 5) 50)) + +(defn cc [amount kind-of-coins] + (cond + (= amount 0) 1 + (or + (< amount 0) + (= kind-of-coins 0)) 0 + (+ + (cc amount (- kind-of-coins 1)) + (cc (- amount (first-denomination kind-of-coins)) kind-of-coins)))) + +(defn count-change [amount] + (cc amount 5)) + +# (cc 11.0 5) +# (cc 11.0 4) (cc -39.0 5) +# (cc 11.0 3) (cc -14.0 4) +# (cc 11.0 2) (cc 1.0 3) +# (cc 11.0 1) (cc 6.0 2) (cc 1.0 2) (cc -9.0 3) +# (cc 11.0 0) (cc 10.0 1) (cc 6.0 1) (cc 1.0 2) (cc 1.0 1) (cc -4.0 2) +# (cc 10.0 0) (cc 9.0 1) (cc 6.0 0) (cc 5.0 1) (cc 1.0 1) (cc -4.0 2) (cc 1.0 0) (cc 0.0 1) +# (cc 9.0 0) (cc 8.0 1) (cc 5.0 0) (cc 4.0 1) (cc 1.0 0) (cc 0.0 1) 1 +# (cc 8.0 0) (cc 7.0 1) (cc 4.0 0) (cc 3.0 1) 1 1 +# (cc 7.0 0) (cc 6.0 1) (cc 3.0 0) (cc 2.0 1) 1 1 +# (cc 6.0 0) (cc 5.0 1) (cc 2.0 0) (cc 1.0 1) 1 1 +# (cc 5.0 0) (cc 4.0 1) (cc 1.0 0) (cc 0.0 1) 1 1 +# (cc 4.0 0) (cc 3.0 1) 1 1 1 +# (cc 3.0 0) (cc 2.0 1) 1 1 1 +# (cc 2.0 0) (cc 1.0 1) 1 1 1 +# (cc 1.0 0) 1 1 1 1 +# 1 1 1 1 +# 4 + +(import ./dot :as dot) + +(defn add-to [graph counter amount kind-of-coins parent] + (def label (string/format "(cc %d %d)" amount kind-of-coins)) + (def node_name (string/format "node_%d" counter)) + (def clr + (cond (= kind-of-coins 0) "lightgray" + (= amount 0) "cyan" + "lightgreen")) + (cond + (= kind-of-coins 2) (dot/add-node (get (get graph :subgraphs) 1) node_name :label label :shape "box" :color clr) + (= kind-of-coins 1) (dot/add-node (get (get graph :subgraphs) 0) node_name :label label :shape "box" :color clr) + (do + (dot/add-node graph node_name :label label :shape "box" :color clr))) + + (dot/add-relation graph parent node_name) + node_name) + +(defn count-change2 [amount denom] + (def graph (dot/create-graph :digraph "change")) + (dot/add-subgraph graph (dot/create-subgraph "rank_1" :rankdir "TB")) + (dot/add-subgraph graph (dot/create-subgraph "rank_2" :rankdir "LR")) + (var counter 0) + (defn cc [amount kind-of-coins parent] + (def name (add-to graph counter amount kind-of-coins parent)) + (set counter (+ counter 1)) + (cond + (= amount 0) 1 + (or + (< amount 0) + (= kind-of-coins 0)) 0 + (+ + (cc amount (- kind-of-coins 1) name) + (cc (- amount (first-denomination kind-of-coins)) kind-of-coins name)))) + + (def result (cc amount denom "test")) + (dot/write-graph graph "exercise_1_14.gv") + result) + +(print (count-change2 11 1)) + +# Using the graph we can find the following relation for (cc n 1) +# f(0,1) = 1 +# f(1,1) = 3 = f(0,1) + 2 +# f(2,1) = 5 = f(1,1) + 2 +# f(3,1) = 7 = f(2,1) + 2 +# f(n,1) = f(n-1, 1) + 2 +# f(n,1) = 2*n + 1 + +# graphing (cc n 2) +# we can see that every iteration of (cc n 2) splits into two trees: +# (cc n 1) and (cc (n-5) 2). +# Starting with f(1,2) = f(-4, 2) + f(1, 1). +# we know that f(1,1) = 3 steps, f(-4, 2) = 1 step, and accounting +# for the original f(1,2), we get a total of 5 steps. +# f(6, 2) = f(1,2) + f(6,1) = 5 + 6 + 1 = 11 +# in general we can say: +# f(n, 2) = f(n, 1) + f(n-x_2, 2) + 1 +# given x_2 = 5 +# example f(1, 2) = f(1, 1) + f(-4, 2) + 1 = 3 + 1 + 1 = 5 +# example f(6, 2) = f(6, 1) + f(1, 2) + 1 = 13 + 5 + 1 = 19 +# the closed form of this is: +# f(n, 2) = ceil(n/5) + sum_i=0^floor(n/5){ f(n-x_2*i, 1) } + (ceil(n/5) - floor(n/5)) +# f(6, 2) = 2 + [f(6, 1) + f(1, 1)] + (2-1) = 2 + 13 + 3 + 1 = 19 +# f(11, 2) = 3 + [f(11, 1) + f(6, 1) + f(1,1)] + (3-2) = 3 + 23 + 13 + 3 + 1 = 43 +# f(n, 2) = 2*ceil(n/5) - floor(n/5) + (ceil(n/5) * (f(n, 1) + f(n%x_2, 1)) / 2) +# f(n, 2) = ceil(n/x_2) * [(f(n,1) + f(n%x_2, 1)) / 2 + 2] - floor(n%x_2) +# f(n, 2) = ceil(n/x_2) * [(2*n + 1 + 2*(n%x_2) + 1) / 2 + 2] - floor(n%x_2) +# f(n, 2) = ceil(n/x_2) * [n + (n-x_2*floor(n/x_2)) + 3] - floor(n/x_2) +# f(11, 2) = 2*3 - 2 + 3 * (23 + 3) / 2 = 6 - 2 + 39 = 43 +# f(11, 2) = 3 * [(23 + 3) / 2 + 2] - 2 = 3 * 45 - 2 = 43 +# f(11, 2) = 3 * [11 + 1 + 3] - 2 = 3 * [15] - 2 = 43 + +# graphing (cc n 3) +# we can see that every iteration of (cc n 3) splits into two trees: +# (cc n 2) + (cc (n-x_3),3) +# an recursive form of this definition would be: +# f(n, 3) = f(n, 2) + f(n-x_2, 3) + 1 +# test: +# f(1, 3) = f(1, 2) + f(-9, 3) + 1 = 5 + 1 + 1 = 7 +# f(11, 3) = f(11, 2) + f(1, 3) + 1 = 43 + 1 + 7 = 51 +