sicp-solutions/ex-2.43.txt
Petar Kapriš 2ca5e73a27 Add solutions to exercises from subsection 2.2.3
Notes:
The exercise 2.37 on Hexlet's site has an error, noted in the comments.
Also, their page for exercise 2.38 should probably have 0 tests.

And finally, I did not calculate the exact number in the final exercise
2.43, but I included a relevant discussion.
2025-02-12 16:16:13 +01:00

62 lines
2.6 KiB
Text

The normal function presented here:
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (rest-of-queens)
(map (lambda (new-row)
(adjoin-position
new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size))
gets executed in roughly the following way: Before any of the calls to filter
or flatmap are performed (queen-cols (- k 1)) will be run. This will happen
recursively, so it will recursively call until (queen-cols 0), which will
return a list with a single empty-board.
Then, in the (queens-col 1) call, eight new boards, each with a single queen,
will be returned, then in the (queens-col 2), 64 will be created, then
filtered, and so forth, each time we exit the current call in the stack, we
have already filtered the results of the previous call.
On the other hand Louis Reasoner's function looks like this:
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (new-row)
(map (lambda (rest-of-queens)
(adjoin-position new-row k rest-of-queens))
(queen-cols (- k 1))))
(enumerate-interval 1 board-size)))))
(queen-cols board-size))
And it first calls enumerate-interval, and generates a list of 8 numbers.
After that, each of these numbers get the outer lambda applied to them, which
then calls (queen-cols 7) eight times. It will then adjoin, and afterwards
filter the results. It should be noted, these sub-calls WILL generate filtered
lists of queens, it's not as if all possible cases will be generated, and only
then filtered, however, each of these recursive subcalls will generate a list
of (queen-cols (- k 1)) eight times, instead of once, and so on recursively.
In other words, for the older version of the function, the execution time T(n)
(assuming board-size is 8), is roughly equal to:
T(n) = T(n-1) + O(8*Q(n-1))
^adjoining and filtering ^
(Q(n-1) is length of result of (queen-cols n))
unraveling this we get: O(Q(n-1)+Q(n-2)+Q(n-3)+...+Q(0))
Whereas the new function's time looks like this:
T(n) = 8*T(n-1) + O(8*Q(n-1))
unraveling, we get, very roughly:
O(8*Q(n-1) + 8*8*Q(n-2) + ... + 8^8*Q(0))
I haven't tried to run the exact numbers, because it would involve learning
exactly what Q(0), ... ,Q(8) are, which I didn't care to do.