WEBVTT

00:00:06.136 --> 00:00:08.270
SRINI DEVADAS: Good
morning, everyone.

00:00:08.270 --> 00:00:10.130
Thanks for coming in
on a Friday morning,

00:00:10.130 --> 00:00:12.680
especially with the
long weekend coming up.

00:00:12.680 --> 00:00:17.900
We're going to pick up
where we left off yesterday.

00:00:17.900 --> 00:00:23.810
And so if you recall,
we were looking

00:00:23.810 --> 00:00:27.710
at an iterative approach
to solving the eight queens

00:00:27.710 --> 00:00:29.150
problem.

00:00:29.150 --> 00:00:32.730
And in case you've
forgotten in the,

00:00:32.730 --> 00:00:37.600
I guess, intervening 20 hours,
the eight queens problem,

00:00:37.600 --> 00:00:41.560
which is a specific
instance of n queens

00:00:41.560 --> 00:00:43.270
is you have a chess board--

00:00:43.270 --> 00:00:45.960
and I won't draw
all the squares--

00:00:45.960 --> 00:00:48.200
which is, obviously,
an 8 by 8 board.

00:00:48.200 --> 00:00:52.530
And you want to place
eight queens on this board

00:00:52.530 --> 00:00:55.220
such that no two queens
attack each other.

00:00:55.220 --> 00:00:58.970
And we looked at different
data structures to solve this.

00:00:58.970 --> 00:01:02.510
The naive data
structure would be

00:01:02.510 --> 00:01:09.860
to represent the board as
a two-dimensional list.

00:01:09.860 --> 00:01:13.120
And so you end up
having an 8 by 8,

00:01:13.120 --> 00:01:15.830
if you have a chessboard for
the eight queens problem.

00:01:15.830 --> 00:01:19.100
We looked at a 4
by 4 for starters.

00:01:19.100 --> 00:01:22.730
And then after that, we
looked at compressing

00:01:22.730 --> 00:01:29.090
that representation down to
a one-dimensional list where

00:01:29.090 --> 00:01:31.670
let's say you had a 5
by 5 board because we've

00:01:31.670 --> 00:01:33.050
got five entries here.

00:01:36.920 --> 00:01:40.670
You exploit the fact that
there can be at most one

00:01:40.670 --> 00:01:43.670
queen on any given column.

00:01:43.670 --> 00:01:46.730
And you say I'm
going to represent

00:01:46.730 --> 00:01:52.490
the position of that queen using
a single number where is from,

00:01:52.490 --> 00:01:58.220
in this case 0 through 4,
if I have a 5 by 5 board,

00:01:58.220 --> 00:02:00.090
and you put that in here.

00:02:00.090 --> 00:02:03.260
So a minus 1 would
represent this being empty.

00:02:03.260 --> 00:02:13.690
A 2 would represent a
queen in the second column

00:02:13.690 --> 00:02:17.110
in this position over
here, et cetera, et cetera.

00:02:17.110 --> 00:02:20.920
So with this more
compact representation,

00:02:20.920 --> 00:02:23.770
it turns out that
the conflict check

00:02:23.770 --> 00:02:27.140
becomes pretty straightforward.

00:02:27.140 --> 00:02:30.820
And if you remember,
our conflict check

00:02:30.820 --> 00:02:34.360
is incremental in the sense
that what you're going to do

00:02:34.360 --> 00:02:39.220
is assume that queens
have already been placed

00:02:39.220 --> 00:02:40.510
in some number of columns.

00:02:40.510 --> 00:02:41.680
I mean, it could be zero.

00:02:41.680 --> 00:02:43.150
In this case it's 2.

00:02:43.150 --> 00:02:45.430
And you're going
to try and check

00:02:45.430 --> 00:02:47.680
to see when a third
queen is placed

00:02:47.680 --> 00:02:50.280
on this third
column, number two,

00:02:50.280 --> 00:02:55.240
whether it conflicts
with the existing queens.

00:02:55.240 --> 00:02:59.372
But you don't have to worry
about the checks associated

00:02:59.372 --> 00:03:01.330
with the existing queens
because you've already

00:03:01.330 --> 00:03:02.560
taken care of that.

00:03:02.560 --> 00:03:05.080
So that's the incremental
nature of this check.

00:03:05.080 --> 00:03:07.570
And I won't go over
this code again,

00:03:07.570 --> 00:03:13.030
but the check
associated with ensuring

00:03:13.030 --> 00:03:20.730
that when you place a
queen on a given column,

00:03:20.730 --> 00:03:21.910
it checks the diagonals.

00:03:21.910 --> 00:03:24.250
That's the most
interesting part.

00:03:24.250 --> 00:03:29.260
And you put a queen here,
you need to check this,

00:03:29.260 --> 00:03:30.920
and you need to check that.

00:03:30.920 --> 00:03:32.950
And in this case, obviously
there's a conflict.

00:03:32.950 --> 00:03:34.741
And because there are
two diagonals, that's

00:03:34.741 --> 00:03:37.060
why you have the ABS, the
absolute value over there,

00:03:37.060 --> 00:03:39.720
and you're exploiting the
fact that the diagonal is

00:03:39.720 --> 00:03:42.790
a diagonal of a square,
and how much you move up

00:03:42.790 --> 00:03:45.910
should be how much you move
to the right or down, left,

00:03:45.910 --> 00:03:47.680
or what have you.

00:03:47.680 --> 00:03:51.670
Another check is simply
ensuring that when

00:03:51.670 --> 00:03:53.670
you look at the
particular column

00:03:53.670 --> 00:03:58.060
and you see the number current
is a particular column,

00:03:58.060 --> 00:04:00.220
the number associated with
that particular column

00:04:00.220 --> 00:04:02.960
shouldn't be repeated
in some other column.

00:04:02.960 --> 00:04:08.470
Because that would imply that
if you saw a 2 and a 2 here,

00:04:08.470 --> 00:04:11.770
obviously, that
would imply that you

00:04:11.770 --> 00:04:16.690
have two queens on the same
row, and you can't have that.

00:04:16.690 --> 00:04:18.000
So that's the story.

00:04:18.000 --> 00:04:23.560
And we decided to use iteration
because, at this point in time,

00:04:23.560 --> 00:04:25.970
you know nothing else in
terms of control flow.

00:04:25.970 --> 00:04:29.350
I know that's not the
case, but we assume that.

00:04:29.350 --> 00:04:32.680
And so you end up
having this ugly code

00:04:32.680 --> 00:04:39.100
associated with eight
nested loops that does

00:04:39.100 --> 00:04:43.960
this incremental enumeration.

00:04:43.960 --> 00:04:52.960
So board 0 being i implies that
you're taking the first column

00:04:52.960 --> 00:04:54.820
and you're iterating
the positions

00:04:54.820 --> 00:04:57.860
of the queen in the rows
of the first column,

00:04:57.860 --> 00:04:59.240
and so on and so forth.

00:04:59.240 --> 00:05:00.670
And if you go
ahead and run this,

00:05:00.670 --> 00:05:02.950
which we did last
time you end up

00:05:02.950 --> 00:05:08.470
getting 92 different solutions
to the eight queens problem,

00:05:08.470 --> 00:05:11.350
and as I mentioned, there's
only 12 distinct ones.

00:05:11.350 --> 00:05:14.410
So if you take rotation
and reflection into account

00:05:14.410 --> 00:05:17.540
and each of these is
a legitimate solution,

00:05:17.540 --> 00:05:20.440
that needs to be
translated into the picture

00:05:20.440 --> 00:05:24.820
that you see here by
essentially taking this data

00:05:24.820 --> 00:05:26.480
structure that you see.

00:05:26.480 --> 00:05:31.300
7 becomes the queen in the
left corner, et cetera.

00:05:31.300 --> 00:05:37.840
So we absolutely wouldn't
want to publish this code.

00:05:37.840 --> 00:05:39.400
I guess, in effect,
I'm doing it.

00:05:39.400 --> 00:05:45.970
But you would not want to
claim authorship of this code

00:05:45.970 --> 00:05:50.500
especially if you know about
the programming technique that's

00:05:50.500 --> 00:05:51.860
called recursion.

00:05:51.860 --> 00:05:53.800
So that's really what
we're going to do today.

00:05:53.800 --> 00:05:56.008
We're going to look at a
couple of different puzzles.

00:05:56.008 --> 00:05:59.320
We'll finish up with the n
queen's puzzle fairly quickly,

00:05:59.320 --> 00:06:02.330
and we'll look at how we
could use recursion, which

00:06:02.330 --> 00:06:05.440
is an algorithm paradigm as
well as a programming paradigm

00:06:05.440 --> 00:06:08.330
to solve challenging problems.

00:06:08.330 --> 00:06:12.010
And there's really
two classes, at least,

00:06:12.010 --> 00:06:14.170
of recursive
algorithms, and you're

00:06:14.170 --> 00:06:15.830
going to see both
of those today.

00:06:15.830 --> 00:06:18.730
The first one is nQueens, and
I'll get to the second one

00:06:18.730 --> 00:06:21.670
when we get to the second one.

00:06:21.670 --> 00:06:27.460
So our goal now is to take that
ugly code and make it pretty.

00:06:27.460 --> 00:06:30.190
And before I get
into that, I want

00:06:30.190 --> 00:06:37.150
to show you a simpler example
of iteration versus recursion.

00:06:37.150 --> 00:06:39.670
And this is about
as simple as it

00:06:39.670 --> 00:06:41.980
gets while still
being interesting

00:06:41.980 --> 00:06:43.730
from an algorithmic standpoint.

00:06:43.730 --> 00:06:49.990
So the greatest common divisor,
Euclid's age-old algorithm

00:06:49.990 --> 00:06:52.480
to compute the greatest
common divisor.

00:06:52.480 --> 00:06:55.300
And you see the two
line, three line,

00:06:55.300 --> 00:06:57.670
what have you
iterative algorithm up

00:06:57.670 --> 00:07:02.590
there that corresponds to taking
the pair of numbers, obviously,

00:07:02.590 --> 00:07:06.700
m and n that you need
to compute the greatest

00:07:06.700 --> 00:07:08.230
common divisor for.

00:07:08.230 --> 00:07:20.320
And all you do is assign m
to n and n becomes n mod m.

00:07:20.320 --> 00:07:23.950
And I'm not going to explain
why this algorithm is correct

00:07:23.950 --> 00:07:25.120
or anything like that.

00:07:25.120 --> 00:07:26.980
I'm not particularly
interested in that.

00:07:26.980 --> 00:07:29.290
What I'm much more
interested in is

00:07:29.290 --> 00:07:34.510
ensuring that you understand
that the iterative algorithm is

00:07:34.510 --> 00:07:37.990
the same as the recursive one.

00:07:37.990 --> 00:07:40.854
The recursive one gets
you the correct answer

00:07:40.854 --> 00:07:42.520
if you assume the
iterative algorithm is

00:07:42.520 --> 00:07:44.830
correct and vice
versa, and that's

00:07:44.830 --> 00:07:46.660
really what this is about.

00:07:46.660 --> 00:07:51.530
So we won't argue if
Euclid is correct or not.

00:07:51.530 --> 00:07:57.440
But the point here is you
could have translated--

00:07:57.440 --> 00:07:59.650
well, you did translate
this iterative algorithm

00:07:59.650 --> 00:08:01.060
into a recursive one.

00:08:01.060 --> 00:08:02.920
And there's a couple
of things I want

00:08:02.920 --> 00:08:06.700
you to keep in mind when
you look at recursive code

00:08:06.700 --> 00:08:08.860
and certainly when you
write recursive code.

00:08:08.860 --> 00:08:11.140
And it's much easier
pointing this out

00:08:11.140 --> 00:08:13.870
in a simple example like this.

00:08:13.870 --> 00:08:19.450
So first off, when
we say recursion--

00:08:19.450 --> 00:08:22.000
and I should have probably said
this a little bit earlier--

00:08:22.000 --> 00:08:26.230
recursion is something
calling itself.

00:08:26.230 --> 00:08:29.980
So you can say a function,
f, calling itself,

00:08:29.980 --> 00:08:32.020
that's the simple case.

00:08:32.020 --> 00:08:34.480
We also consider if
you have f calling

00:08:34.480 --> 00:08:42.049
g, which calls f, then
that is recursive as well.

00:08:42.049 --> 00:08:45.070
And see you can have
arbitrary structures that

00:08:45.070 --> 00:08:46.920
correspond to nested recursion.

00:08:46.920 --> 00:08:51.660
We're really only going
to be looking at functions

00:08:51.660 --> 00:08:55.390
at least in this lecture, where
you have a single function, f,

00:08:55.390 --> 00:08:58.210
calling itself, which
is exactly the case

00:08:58.210 --> 00:09:01.880
for our RGCD, the Recursive
GCD that you see here.

00:09:01.880 --> 00:09:05.530
You see a call RGCD
inside of RGCD,

00:09:05.530 --> 00:09:07.270
and you know this
function is recursive.

00:09:07.270 --> 00:09:09.730
Sometimes you may
look at a function

00:09:09.730 --> 00:09:15.070
and you don't see that
immediate syntactic evidence

00:09:15.070 --> 00:09:19.330
that the function is recursive,
but it may be recursive

00:09:19.330 --> 00:09:23.740
because of nested
recursion, f calling

00:09:23.740 --> 00:09:26.240
g, more complicated recursion.

00:09:26.240 --> 00:09:29.650
So this is clearly a
recursive function, RGCD.

00:09:29.650 --> 00:09:34.870
And two things that
you need to look

00:09:34.870 --> 00:09:38.620
for if you want to write
correct recursion, I mean this

00:09:38.620 --> 00:09:41.300
is not sufficient to
write correct recursion,

00:09:41.300 --> 00:09:43.450
but necessary.

00:09:43.450 --> 00:09:46.930
And in particular, when
I say correct recursion,

00:09:46.930 --> 00:09:52.220
I want it to be
non-terminating, so the problem

00:09:52.220 --> 00:09:56.230
with something calling itself
is, you think of it as there's

00:09:56.230 --> 00:09:59.334
some sort of cycle
and you absolutely

00:09:59.334 --> 00:10:01.250
need to break out of the
cycle, otherwise, you

00:10:01.250 --> 00:10:02.770
will be in the cycle forever.

00:10:02.770 --> 00:10:05.970
You could call something
which calls something, which

00:10:05.970 --> 00:10:08.260
calls something that
goes on, your program

00:10:08.260 --> 00:10:09.807
isn't going to terminate.

00:10:09.807 --> 00:10:12.390
So you always want to be careful
when you write recursive code

00:10:12.390 --> 00:10:14.900
that there's a base case.

00:10:14.900 --> 00:10:16.970
There's a termination condition.

00:10:16.970 --> 00:10:20.560
So there should be
some part of the code

00:10:20.560 --> 00:10:25.030
where if certain
conditions are satisfied,

00:10:25.030 --> 00:10:27.880
you're not making
a recursive call.

00:10:27.880 --> 00:10:29.920
That is what I would
consider the base case.

00:10:29.920 --> 00:10:32.770
That really comes from induction
and from the mathematics

00:10:32.770 --> 00:10:33.820
of recursion.

00:10:33.820 --> 00:10:36.190
You want to have a base
case and then the recursion

00:10:36.190 --> 00:10:38.770
is really the inductive step.

00:10:38.770 --> 00:10:41.620
If that doesn't make too much
sense, don't worry about it.

00:10:41.620 --> 00:10:43.330
You can think of
it syntactically.

00:10:43.330 --> 00:10:45.490
Look for a path in
the code where you

00:10:45.490 --> 00:10:48.220
don't see RGCD inside of RGCD.

00:10:48.220 --> 00:10:52.180
And you can clearly see
that in the if m mod n

00:10:52.180 --> 00:10:54.370
equals equals 0, return n.

00:10:57.520 --> 00:11:00.310
So you want to have
what we call the base

00:11:00.310 --> 00:11:07.150
case where a function returns.

00:11:10.660 --> 00:11:12.670
That's not enough
because you don't quite

00:11:12.670 --> 00:11:15.940
know if you're going to get
to that base case or not.

00:11:15.940 --> 00:11:19.900
You're going to call this
function with some arguments,

00:11:19.900 --> 00:11:22.780
and you want to get some
sense that the arguments are

00:11:22.780 --> 00:11:25.666
shrinking as you go.

00:11:25.666 --> 00:11:27.415
And it could even be
the other way around.

00:11:27.415 --> 00:11:30.370
The arguments may
increase, and once you

00:11:30.370 --> 00:11:34.240
grow beyond a certain threshold,
you fire off on the return

00:11:34.240 --> 00:11:37.390
without making the
recursive call.

00:11:37.390 --> 00:11:41.050
So this notion of the
arguments becoming smaller

00:11:41.050 --> 00:11:46.090
is very common in the case
of the algorithmic paradigm

00:11:46.090 --> 00:11:47.930
that we'll be
following in this class

00:11:47.930 --> 00:11:50.200
where we're going to take
large problems like a eight

00:11:50.200 --> 00:11:53.700
queens or n queens and
go to n minus 1 queens

00:11:53.700 --> 00:11:55.300
and n minus 2 queens.

00:11:55.300 --> 00:11:59.800
And divide and conquer, which is
other paradigm that we look at.

00:11:59.800 --> 00:12:03.130
As you can see from the
name is taking a big problem

00:12:03.130 --> 00:12:05.080
and making it smaller.

00:12:05.080 --> 00:12:07.030
So really for the
most part, you're

00:12:07.030 --> 00:12:10.270
going to essentially have
a situation where you're

00:12:10.270 --> 00:12:19.240
going to say that the
arguments to the function

00:12:19.240 --> 00:12:25.280
should be smaller in some sense.

00:12:25.280 --> 00:12:27.590
And smaller could mean bigger.

00:12:27.590 --> 00:12:29.420
I mean, it's just a
definitional thing.

00:12:29.420 --> 00:12:33.080
I mean, the point is when
you get to the base case,

00:12:33.080 --> 00:12:35.750
usually you are saying, as
you can see in this base case,

00:12:35.750 --> 00:12:38.220
you're saying when it
comes down to the fact

00:12:38.220 --> 00:12:41.660
that a particular condition
is satisfied, in this case,

00:12:41.660 --> 00:12:43.760
it's the relationship
between m and n.

00:12:43.760 --> 00:12:45.920
And if that's 0,
then we return n.

00:12:45.920 --> 00:12:47.630
But in other cases,
it just might

00:12:47.630 --> 00:12:51.950
be when you get to a one
queen problem, you're done.

00:12:51.950 --> 00:12:53.390
I mean, you have no choice.

00:12:53.390 --> 00:12:55.070
You've got this 1 by
1 board and you've

00:12:55.070 --> 00:12:57.500
got to put your queen on
it, and obviously, that

00:12:57.500 --> 00:13:00.080
might create a conflict,
but you're done.

00:13:00.080 --> 00:13:01.790
I mean, there's no
two things about it

00:13:01.790 --> 00:13:03.290
if you have one queen problem.

00:13:03.290 --> 00:13:04.960
There's only one step.

00:13:04.960 --> 00:13:07.310
You put your queen down.

00:13:07.310 --> 00:13:10.250
So that's where we were at
with respect to the puzzles

00:13:10.250 --> 00:13:12.410
that we're going to
be doing in this class

00:13:12.410 --> 00:13:15.590
where you're going to
shrink things down.

00:13:15.590 --> 00:13:20.360
So in that sense, smaller
would mean smaller.

00:13:20.360 --> 00:13:22.810
It's not necessarily in quotes.

00:13:22.810 --> 00:13:23.690
So that makes sense?

00:13:23.690 --> 00:13:26.630
Any questions at all
about syntax or anything

00:13:26.630 --> 00:13:29.940
that you see on the board here?

00:13:29.940 --> 00:13:31.110
All right good.

00:13:31.110 --> 00:13:40.990
So now, I'm ready to show
you what the n queens

00:13:40.990 --> 00:13:42.239
code looks like.

00:13:42.239 --> 00:13:43.780
One of the other
problems, of course,

00:13:43.780 --> 00:13:51.440
with the eight queens
code is that it only

00:13:51.440 --> 00:13:55.820
works for eight queens, and
it doesn't work for nine.

00:13:55.820 --> 00:14:00.290
And that's annoying,
so you'd like

00:14:00.290 --> 00:14:05.720
to have a procedure that takes
n as an argument and works

00:14:05.720 --> 00:14:08.510
for n equals 4, n equals 8.

00:14:08.510 --> 00:14:11.030
And eventually, you could
run this on n equals 20,

00:14:11.030 --> 00:14:12.260
and it will finish.

00:14:12.260 --> 00:14:13.350
I'll show you.

00:14:13.350 --> 00:14:16.550
But there is an
exponential relationship

00:14:16.550 --> 00:14:21.330
between run time and
n because it's just

00:14:21.330 --> 00:14:22.560
a complicated problem.

00:14:22.560 --> 00:14:24.090
There's a lot of combinations.

00:14:24.090 --> 00:14:27.880
So you do not want to run this
code for more than n equals 25.

00:14:27.880 --> 00:14:29.810
It hasn't completed.

00:14:29.810 --> 00:14:33.590
I think at some point I
did an analysis on how long

00:14:33.590 --> 00:14:37.009
it would take for n
equals 30, and it wasn't

00:14:37.009 --> 00:14:38.300
something I wanted to wait for.

00:14:38.300 --> 00:14:40.430
I mean, my computer
would have gotten old

00:14:40.430 --> 00:14:44.720
and died before the
program came back.

00:14:44.720 --> 00:14:47.360
Which is a reasonable
experiment to carry out,

00:14:47.360 --> 00:14:49.490
but I like my computer.

00:14:49.490 --> 00:14:52.760
I'm kind of annoyed with it
because of the new operating

00:14:52.760 --> 00:14:55.310
system, but I generally like it.

00:14:55.310 --> 00:14:57.710
So you can see that
we're going to use

00:14:57.710 --> 00:14:59.710
exactly the same framework.

00:14:59.710 --> 00:15:04.080
We're going to use the
same no conflicts routine.

00:15:04.080 --> 00:15:07.460
There's no change there, no
change in data structures.

00:15:07.460 --> 00:15:10.160
There's no change in really
even the incremental strategy

00:15:10.160 --> 00:15:11.650
that we're following.

00:15:11.650 --> 00:15:13.640
But we can take
that intuitive code

00:15:13.640 --> 00:15:16.910
and turn it into this pretty
code that has about five lines,

00:15:16.910 --> 00:15:19.740
or seven lines, what have you.

00:15:19.740 --> 00:15:23.060
And so you can see, again,
that if you look at that code,

00:15:23.060 --> 00:15:24.960
I mean, it's not that
much more complicated.

00:15:24.960 --> 00:15:26.789
There's more going on in there.

00:15:26.789 --> 00:15:29.330
There's more going on because
it's a more interesting problem

00:15:29.330 --> 00:15:35.780
at some level than GCD, but it
has the same characteristics

00:15:35.780 --> 00:15:39.650
in terms of having a base case,
and it's actually an easy one

00:15:39.650 --> 00:15:40.370
to look at.

00:15:40.370 --> 00:15:44.270
And it also has
a property 2 here

00:15:44.270 --> 00:15:46.490
where the argument
to the nQueens

00:15:46.490 --> 00:15:51.050
is going to be one less than
what the caller function has

00:15:51.050 --> 00:15:53.780
as its argument because
you're going column by column,

00:15:53.780 --> 00:15:55.410
and you're taking away.

00:15:55.410 --> 00:15:58.760
In this case, you're not
necessarily going to a 7

00:15:58.760 --> 00:16:00.470
by 7, really.

00:16:00.470 --> 00:16:04.280
It's not that you're going
from 8 by 8 to 7 by 7.

00:16:04.280 --> 00:16:07.340
You're going from
8 by 8 to 7 by 8.

00:16:09.920 --> 00:16:11.250
You have one less column.

00:16:11.250 --> 00:16:14.990
You still have to work
with all the rows.

00:16:14.990 --> 00:16:16.830
So that's really what's
going on out here.

00:16:16.830 --> 00:16:18.600
If current equal size--

00:16:18.600 --> 00:16:22.400
so what's happening is current
is actually incrementing.

00:16:22.400 --> 00:16:28.820
So you're moving and what is
remaining is becoming smaller.

00:16:28.820 --> 00:16:31.710
And current starts with--

00:16:31.710 --> 00:16:34.980
so if you look at
nQueens here, it

00:16:34.980 --> 00:16:39.170
says nQueens, a
size, and rQueens,

00:16:39.170 --> 00:16:47.120
which is this routine here,
it sets current to be 0.

00:16:47.120 --> 00:16:50.540
And size is, of course,
whatever you give nQueens,

00:16:50.540 --> 00:16:53.010
which could be 8 or 20.

00:16:53.010 --> 00:17:00.290
And finally, if you look
at this part of the code,

00:17:00.290 --> 00:17:02.060
you get to the point
where you run out

00:17:02.060 --> 00:17:04.490
of columns when
current equals size.

00:17:04.490 --> 00:17:07.730
And at this point, you
put all the queens down,

00:17:07.730 --> 00:17:10.010
and that things
haven't fallen apart--

00:17:10.010 --> 00:17:11.630
you haven't returned false--

00:17:11.630 --> 00:17:14.150
and therefore, you're done.

00:17:14.150 --> 00:17:16.880
So when you get to that
quote ninth column,

00:17:16.880 --> 00:17:19.210
you're off the board,
and you're done.

00:17:19.210 --> 00:17:21.829
And all of the existing
queens, the eight queens

00:17:21.829 --> 00:17:23.690
that were put on
the board, didn't

00:17:23.690 --> 00:17:25.460
conflict with each other.

00:17:25.460 --> 00:17:27.140
That's how it works.

00:17:27.140 --> 00:17:31.859
And then over here, you've
taken your eight loops that

00:17:31.859 --> 00:17:34.400
were in the eight queens problem
or the for loops in the four

00:17:34.400 --> 00:17:37.800
queens problem and
you've gone off

00:17:37.800 --> 00:17:39.860
and turned it into one loop.

00:17:39.860 --> 00:17:41.810
And the reason that
works is because rQueens

00:17:41.810 --> 00:17:43.430
is calling rQueens out here.

00:17:43.430 --> 00:17:46.610
So that's your recursive call.

00:17:46.610 --> 00:17:51.080
And then the argument
here is current plus 1,

00:17:51.080 --> 00:17:53.120
and it's getting closer
and closer to size

00:17:53.120 --> 00:17:56.150
as you go around, which
means that it's effectively

00:17:56.150 --> 00:17:57.950
getting smaller.

00:17:57.950 --> 00:18:01.160
What you're working
with is getting smaller.

00:18:01.160 --> 00:18:04.280
So if of look at
what happens here,

00:18:04.280 --> 00:18:07.610
you can trace the
execution of this,

00:18:07.610 --> 00:18:09.560
and this is worthwhile doing.

00:18:09.560 --> 00:18:13.490
And I'll put this in the notes,
and you can look at it for a 4

00:18:13.490 --> 00:18:14.360
by 4.

00:18:14.360 --> 00:18:18.030
But in general, if you're
confused about recursion,

00:18:18.030 --> 00:18:20.780
it's absolutely
worthwhile to trace

00:18:20.780 --> 00:18:24.650
the execution for
small arguments

00:18:24.650 --> 00:18:27.710
and figure out exactly
when things are terminating

00:18:27.710 --> 00:18:30.920
and when things are
being called recursively.

00:18:30.920 --> 00:18:34.325
And this is simply
a single call.

00:18:39.500 --> 00:18:45.920
It looks like it's a single
call, because there's

00:18:45.920 --> 00:18:47.750
only one instance of rQueens.

00:18:47.750 --> 00:18:51.700
But if you look at the
code, how many calls would

00:18:51.700 --> 00:18:56.590
I possibly make if I were
sitting with an eight queens

00:18:56.590 --> 00:19:03.280
problem and I started
with size equals 8?

00:19:03.280 --> 00:19:06.070
Then in that very
first, I invoke rQueens

00:19:06.070 --> 00:19:10.130
with current equal
0 and size equals 8.

00:19:10.130 --> 00:19:13.360
How many rQueens calls will
the first rQueens make?

00:19:18.120 --> 00:19:22.130
How many times would
potentially make that?

00:19:22.130 --> 00:19:26.810
So if I look at the branching
here and I say this is rQueens

00:19:26.810 --> 00:19:34.610
and this has current
equals 0 and size equals 8,

00:19:34.610 --> 00:19:39.310
the way you want to think about
this from a tracing standpoint

00:19:39.310 --> 00:19:41.960
is you're making calls.

00:19:41.960 --> 00:19:44.690
rQueens is calling rQueens.

00:19:44.690 --> 00:19:48.320
And obviously, there is
rQueens in the middle

00:19:48.320 --> 00:19:51.360
of that code over there.

00:19:51.360 --> 00:19:54.680
And so what is the
breadth here in terms

00:19:54.680 --> 00:19:56.010
of the number of calls?

00:19:58.617 --> 00:19:59.116
Someone?

00:20:04.660 --> 00:20:05.600
Trace the code.

00:20:05.600 --> 00:20:10.010
So i in range 8, which
means 0 through 7,

00:20:10.010 --> 00:20:13.480
and then I'm going to go off,
and this is the very first one.

00:20:13.480 --> 00:20:17.150
So noConflicts is going
to constantly return--

00:20:17.150 --> 00:20:18.650
it's the first queen.

00:20:18.650 --> 00:20:21.950
So noConflicts is going
to constantly return true.

00:20:21.950 --> 00:20:24.350
So I'm going to go
inside of the if,

00:20:24.350 --> 00:20:27.220
and I'm going to make
that rQueens call.

00:20:27.220 --> 00:20:31.040
So I'm going to have eight
different calls associated

00:20:31.040 --> 00:20:32.990
with each of the
positions that corresponds

00:20:32.990 --> 00:20:36.440
to the queen on
that first column.

00:20:36.440 --> 00:20:40.280
And then each of these
could potentially

00:20:40.280 --> 00:20:43.890
make eight different
calls, potentially I

00:20:43.890 --> 00:20:46.640
said because as you get
deeper in the recursion,

00:20:46.640 --> 00:20:49.820
the noConflicts is
going to fire false,

00:20:49.820 --> 00:20:51.892
and it may not make the call.

00:20:51.892 --> 00:20:53.600
But obviously, the
very first one, you're

00:20:53.600 --> 00:20:55.320
going to make eight calls.

00:20:55.320 --> 00:21:00.670
So recursion is scary from
a performance standpoint

00:21:00.670 --> 00:21:05.294
to some people and rightly so
because things could explode

00:21:05.294 --> 00:21:06.710
on you, and this
goes back to what

00:21:06.710 --> 00:21:10.680
I said about running
this with n r size

00:21:10.680 --> 00:21:12.630
equals 25 and so
on and so forth.

00:21:12.630 --> 00:21:14.510
And one of the things
that is worth doing

00:21:14.510 --> 00:21:23.240
and you have to do this type of
analysis in classes like 6.006,

00:21:23.240 --> 00:21:25.310
not a lot of this
but because we don't

00:21:25.310 --> 00:21:27.050
do exponential algorithms.

00:21:27.050 --> 00:21:30.020
But you can look
at this tree that

00:21:30.020 --> 00:21:32.820
is being generated by
these recursive calls

00:21:32.820 --> 00:21:36.140
and you do want to get some
sense of how large this tree is

00:21:36.140 --> 00:21:37.300
going to become.

00:21:37.300 --> 00:21:39.807
And we're going to look at a
different class of algorithms.

00:21:39.807 --> 00:21:41.390
Most of algorithms
we're going to look

00:21:41.390 --> 00:21:45.920
at that are recursive for the
rest of this course including

00:21:45.920 --> 00:21:49.700
the next one that we'll
get to in a few minutes,

00:21:49.700 --> 00:21:52.100
aren't as bad as
this one in terms

00:21:52.100 --> 00:21:54.620
of computational complexity.

00:21:54.620 --> 00:21:56.420
But n queens is a hard problem.

00:21:56.420 --> 00:22:00.570
It needs exhaustive search, and
there's a lot of combinations.

00:22:00.570 --> 00:22:02.960
And so it's not an
efficient algorithm.

00:22:02.960 --> 00:22:05.450
Efficient means
polynomial times something

00:22:05.450 --> 00:22:09.180
like n square quadratic,
n cubed, and so on.

00:22:09.180 --> 00:22:11.630
And this is not efficient,
and the reason for that

00:22:11.630 --> 00:22:14.630
is this explosion in the
number of recursive calls.

00:22:14.630 --> 00:22:17.990
So it's easy to write five
lines of code that takes forever

00:22:17.990 --> 00:22:18.830
to run.

00:22:18.830 --> 00:22:19.700
It will terminate.

00:22:19.700 --> 00:22:21.680
It's not that it had
an infinite loop in it,

00:22:21.680 --> 00:22:24.500
but the number of combinations
explodes on you because

00:22:24.500 --> 00:22:32.300
of eight and then eight again
for each of these and then--

00:22:32.300 --> 00:22:32.850
and so on.

00:22:32.850 --> 00:22:36.980
So you can see that gets
pretty large pretty quick.

00:22:36.980 --> 00:22:45.800
So this code is something
that, as I said,

00:22:45.800 --> 00:22:47.990
is essentially the same.

00:22:47.990 --> 00:22:51.350
It's sitting there
computing nQueens 20.

00:22:51.350 --> 00:22:54.590
That's why this is not a problem
with my laptop, at least,

00:22:54.590 --> 00:22:58.467
as of this moment, I don't think
it's a problem with my laptop.

00:22:58.467 --> 00:22:59.300
And so there you go.

00:22:59.300 --> 00:23:07.140
So nQueens 20 gave you the
representation that we chose.

00:23:07.140 --> 00:23:09.350
You can try and
convince yourself

00:23:09.350 --> 00:23:11.780
that this, in fact, is correct.

00:23:11.780 --> 00:23:13.410
I haven't.

00:23:13.410 --> 00:23:16.790
But that code is so
straightforward at this point

00:23:16.790 --> 00:23:20.200
that if there is
anything wrong with it,

00:23:20.200 --> 00:23:22.850
it would be
catastrophically wrong.

00:23:22.850 --> 00:23:26.680
It would just crash or it
wouldn't return anything.

00:23:26.680 --> 00:23:28.620
And so that is one solution.

00:23:28.620 --> 00:23:29.900
There's many, many solutions.

00:23:29.900 --> 00:23:33.710
Unlike the eight queens case,
where I ran it to completion

00:23:33.710 --> 00:23:36.200
and all the 92 solutions
got printed out,

00:23:36.200 --> 00:23:38.100
there's millions
of solutions here.

00:23:38.100 --> 00:23:41.180
So if I just took out a return
statement and let it run,

00:23:41.180 --> 00:23:44.030
you'll get screen
fulls of solutions

00:23:44.030 --> 00:23:49.700
to the 20 queens problem
because if you did that, there

00:23:49.700 --> 00:23:50.990
would be a lot of solutions.

00:23:50.990 --> 00:23:52.820
But especially given
that we are not

00:23:52.820 --> 00:23:56.960
exploiting rotational
symmetry and reflections,

00:23:56.960 --> 00:23:58.880
there's a lot of solutions.

00:23:58.880 --> 00:24:00.230
But that's one of them.

00:24:00.230 --> 00:24:02.870
So there you go.

00:24:02.870 --> 00:24:03.650
Yeah.

00:24:03.650 --> 00:24:04.150
Question.

00:24:04.150 --> 00:24:05.770
AUDIENCE: Is there an expression
for the number of solutions

00:24:05.770 --> 00:24:07.706
you'll get, that depends on n?

00:24:07.706 --> 00:24:08.660
SRINI DEVADAS: No.

00:24:08.660 --> 00:24:10.161
There's no closed form solution.

00:24:10.161 --> 00:24:10.660
No.

00:24:13.650 --> 00:24:19.790
The 12 is a concrete number,
and 92 and 12 were enumerated.

00:24:19.790 --> 00:24:22.991
Now you could obviously write a
computer program that counted--

00:24:22.991 --> 00:24:24.740
I mean, you didn't
have to print this out.

00:24:24.740 --> 00:24:26.780
You could count the
number of solutions

00:24:26.780 --> 00:24:30.060
to the 20 queens problem,
and you can find that out.

00:24:30.060 --> 00:24:32.360
But then if you want to do
rotations and reflections,

00:24:32.360 --> 00:24:34.230
you'd have to start
shaving things off.

00:24:34.230 --> 00:24:34.970
Yeah, back there.

00:24:34.970 --> 00:24:37.345
AUDIENCE: Do you have the run
time for the recursive one?

00:24:37.345 --> 00:24:38.734
Would that be n to the n?

00:24:38.734 --> 00:24:40.010
SRINI DEVADAS: No.

00:24:40.010 --> 00:24:41.780
Because you're doing
significant pruning.

00:24:41.780 --> 00:24:43.200
Great question.

00:24:43.200 --> 00:24:49.250
So some of these things get
truncated because you end up

00:24:49.250 --> 00:24:52.002
doing this, and
then this one you

00:24:52.002 --> 00:24:53.210
don't have to go any further.

00:24:56.240 --> 00:25:00.530
So it's not n to the n
simply because you never

00:25:00.530 --> 00:25:05.510
have to put down another
queen if the first two queens

00:25:05.510 --> 00:25:08.850
conflict with each other.

00:25:08.850 --> 00:25:11.350
So you likely did,
actually, been back

00:25:11.350 --> 00:25:14.470
on Thursday about
this time yesterday,

00:25:14.470 --> 00:25:16.600
we were going over the 4 by 4.

00:25:16.600 --> 00:25:19.930
And we didn't even
put a queen down.

00:25:19.930 --> 00:25:22.760
We went over and we
said, oh, this clearly

00:25:22.760 --> 00:25:26.710
can't work because there's
a queen on this row already.

00:25:26.710 --> 00:25:29.680
This clearly can't work because
there's a queen one a way.

00:25:29.680 --> 00:25:31.600
So there's no
reason to go deeper.

00:25:31.600 --> 00:25:37.780
You would go n raised to n if
you only did the conflict check

00:25:37.780 --> 00:25:40.540
after you put n queens down.

00:25:40.540 --> 00:25:42.520
And if you put
all n queens down,

00:25:42.520 --> 00:25:45.070
closed your eyes put n queens
down and then ran a conflict

00:25:45.070 --> 00:25:47.530
check, and then did
that over and over,

00:25:47.530 --> 00:25:49.840
over and over, it
would be n raised to n.

00:25:49.840 --> 00:25:51.620
But that's not what we're doing.

00:25:51.620 --> 00:25:56.020
What we're doing is if you look
at the code, we are saying if--

00:25:56.020 --> 00:25:58.960
this is an important
statement, actually.

00:25:58.960 --> 00:26:00.340
Thanks for the question.

00:26:00.340 --> 00:26:02.110
That is pruning your
search, and that

00:26:02.110 --> 00:26:05.914
is making it significantly
less than n raised to n.

00:26:05.914 --> 00:26:06.580
A nice exercise.

00:26:06.580 --> 00:26:09.540
Remember what I said about
opportunity for homework,

00:26:09.540 --> 00:26:11.070
when I get questions.

00:26:11.070 --> 00:26:14.620
A nice exercise is to
go to 8 raised to 8

00:26:14.620 --> 00:26:19.930
and then go to the
eight queens problem

00:26:19.930 --> 00:26:21.430
and figure out
what that number is

00:26:21.430 --> 00:26:23.740
in terms of the number
of times you're actually

00:26:23.740 --> 00:26:25.270
checking for no conflicts.

00:26:25.270 --> 00:26:28.150
So count the number of times,
not the number of solutions,

00:26:28.150 --> 00:26:31.266
but the number of times
noConflicts is being called,

00:26:31.266 --> 00:26:33.390
and you'll find that it's
significantly less than 8

00:26:33.390 --> 00:26:34.954
raised to 8.

00:26:34.954 --> 00:26:36.370
Because you're
pruning the search.

00:26:38.980 --> 00:26:44.230
Technically, it's called pruning
the search high up in the tree.

00:26:44.230 --> 00:26:47.140
That's the technical
term for it.

00:26:47.140 --> 00:26:47.840
All right?

00:26:47.840 --> 00:26:48.640
Good.

00:26:48.640 --> 00:26:49.860
Any other questions?

00:26:52.520 --> 00:26:56.200
So we're done with eight
queens and nQueens.