#| changer : (listof N) N -> (listof N) (define (changer actual-coins amount) ...) Assumption: actual-coins is sorted in descending order Purpose: produce a sub-list of actual-coins that represents amount the "coins" on the output are in the same order as those in actual-coins Examples: (changer (list 25 25 10 10 10 10 5 1 1) 55) = (list 25 25 5) (changer (list 25 25 10 10 10 10 5 1 1) 65) = (list 25 25 10 5) |# (define (changer actual-coins amount) (cond ((and (empty? actual-coins) (= amount 0)) empty) ((and (cons? actual-coins) (= amount 0)) empty) ((and (empty? actual-coins) (> amount 0)) ?????) (else (cond [(< amount (first actual-coins)) (changer (rest actual-coins) amount)] [else ; (<= amount (first actual-coins)) (cons (first actual-coins) (changer (rest actual-coins) (- amount (first actual-coins))))]))))
What is different about this function? -- It does not recur on the structure of the second argument! Instead, the second argument represents how much we have changed, starting from the original.
(changer (list 25 25 10 10 10 10 5 1 1) 55) = (cons 25 (changer (list 25 10 10 10 10 5 1 1) 30)) = (cons 25 (cons 25 (changer (list 10 10 10 10 5 1 1) 5))) = (cons 25 (cons 25 (changer (list 10 10 10 5 1 1) 5))) = (cons 25 (cons 25 (changer (list 10 10 5 1 1) 5))) = (cons 25 (cons 25 (changer (list 10 5 1 1) 5))) = (cons 25 (cons 25 (changer (list 5 1 1) 5))) = (cons 25 (cons 25 (cons 5 (changer (list 1 1) 0)))) = (list 25 25 5)
Here is a representation of this new graph:
(define Graph-cycle '((A (B E)) (B (E F)) (C (B D)) (D ()) (E (C F)) (F (D G)) (G ())))The only difference between Graph and Graph-with-cycle is that the latter contains B as a neighbor of C.
Our plain old find-route program won't work anymore:
(find-route 'A 'D Graph-cycle) = (find-route 'B 'D Graph-cycle) = (find-route 'E 'D Graph-cycle) = (find-route 'C 'D Graph-cycle) = (find-route 'B 'D Graph-cycle)Since the first neighbor of A is B, the algorithm attempts to find a path that leads through B. Unfortunately, the path that starts from B contains the above cycle, and therefore the program never terminates.
What to do? Hint: use an accumulator.
We can introduce an "accumulator" argument that keeps track of what origination nodes the algorithm has visited. Then, when it discovers a cycle, the attempt to find a route has failed.
(define (find-route O D graph visited) (cond ((eq? O D) (list D)) ((member O visited) #f) (else (local ((define route (try-all-neighbors (neighbors O graph) D graph (cons O visited)))) (cond ((boolean? route) #f) (else (cons O route))))))) (define (try-all-neighbors lo-Os D graph visited) (cond ((empty? lo-Os) #f) (else (local ((define route (find-route (first lo-Os) D graph visited))) (cond ((boolean? route) (try-all-neighbors (rest lo-Os) D graph visited)) (else route))))))And yes, the new definition works:
(find-route 'A 'D Graph-cycle empty) = (list 'A 'B 'E 'C 'D)
Let's wrap it up in a local:
(define (find-route O D graph) (local ((define (find-route O D visited) (cond ((eq? O D) (list D)) ((member O visited) #f) (else (local ((define route (try-all-neighbors (neighbors O graph) D (cons O visited)))) (cond ((boolean? route) #f) (else (cons O route))))))) (define (try-all-neighbors lo-Os D visited) (cond ((empty? lo-Os) #f) (else (local ((define route (find-route (first lo-Os) D visited))) (cond ((boolean? route) (try-all-neighbors (rest lo-Os) D visited)) (else route))))))) (find-route O D empty)))
Matthias Felleisen | This page was generated on Fri Apr 9 09:17:38 CDT 1999. |