Q1: 35 points Q2: 25+10 points Q3: 40 points Total: 100+10 points
Question text is in black, solutions in blue.
Here are several definitions used on the exam.
Remember that natural always means "non-negative integer".
Generalized Fibonacci Numbers:: If a and b are any two naturals, we define the function Ga,b by the rules (1) Ga,b(0) = a, (2) Ga,b(1) = b, and (3) (for n ≥ 1) Ga,b(n+1) = Ga,b(n) + Ga,b(n-1). Note that the ordinary Fibonacci numbers, as defined in Discussion #7, are defined by F(n) = G0,1(n).
A Function From Binary Strings to Integers: Let Σ = {0, 1}, so that Σ* is the set of all binary strings, including the empty string λ. We define the function f from Σ* to the integers, recursively by the rules (1) f(λ) = 0, (2) for any string w, f(w0) = 1 - f(w), and (3) for any string w, f(w1) = 1 + f(w). (Here "w0" is the string made by appending a 0 to w, and similarly for "w1".)
A Labelled Directed Graph: We will look at several searches of the following labelled directed graph G. Each edge goes in only one direction and is labelled by its cost.
1 2
[a] -----> [b] -----> [c]
^ | |
| 1 | 1 | 3
| | |
| 5 V 4 V
[s] -----> [d] -----> [g]
| | ^
| 6 | 1 | 1
| | |
V 3 V 1 |
[e] -----> [f] -----> [j]
A Heuristic: For an A* search of G with goal node g, we will use the following heuristic. For any node x in g, the function h(x) will give the smallest number of edges on any path from x to g. Thus h(a) = h(e) = 3, h(b) = h(s) = h(f) = 2, h(c) = h(d) = h(j) = 1, and h(g) = 0.
(I'm going to leave off the subscripts on Ga,b throughout this problem, as we are never changing a or b during any part.) Here we have G(0) = 4, G(1) = 2, G(2) = 6, G(3) = 8, G(4) = 14, G(5) = 22, G(6) = 36, G(7) = 58, G(8) = 94, G(9) = 152, and G(10) = 246. So the answer is 22.
Strong induction on n. Let P(n) be the statement "G(n) is a natural". First base case, G(0) = a, which is a natural. Second base case, G(1) = b, which is a natural. For the inductive case, let n be arbitrary and assume that n ≥ 1. The SIH says that for any i with i ≤ n, G(i) is a natural. So G(n) and G(n-1) are naturals, and G(n+1) = G(n) + G(n-1) is the sum of two naturals, which is a natural. This proves P(n+1) from the strong IH, completing the strong induction proof of ∀n:P(n).
Here is the non-inductive proof first. Let n be arbitrary and assume
that n ≥ 1. (I generally took off a point for not saying "let
n be arbitrary" or otherwise indicating the context of n.) We
know that G(n+1) = G(n) + G(n-1). G(n-1) is a natural by part
(b).
So G(n+1) is equal to G(n) plus a natural, and must be ≥ G(n).
Here's the inductive proof, using strong induction starting with n
= 1. Our P(n) is "G(n+1) ≥ G(n)". Note that P(0) could well be
false. Base case: When n = 1, G(2) = a + b and G(1) = b, and G(2)
≥ G(1) because a is a natural. For the inductive case, let n be
arbitrary and assume n ≥ 1. We could just ignore the SIH and say
that
G(n+1) = G(n) plus a natural, as above. But we could also use the
SIH,
which says that G(n+1) ≥ G(n) and G(n) ≥ G(n-1). (To get this
latter fact we need that n-1 ≥ 1, but if n = 1 we are done by the
base
case.)
If I take the two inequalities G(n+1) ≥ G(n) and G(n) ≥
G(n-1)
and add them, I get G(n+1) + G(n) ≥ G(n) + G(n-1), which by
applying the definition of G to both sides becomes G(n+2) ≥
G(n+1).
This proves P(n+1) from the SIH and completes the strong induction.
Let n be arbitrary and assume that n ≥ 2. (Here the bounds on n are important, so you needed to say something about the context of n to get full credit.) Applying the definition, G(n+3) = G(n+2) + G(n+1) = G(n+1) + G(n) + G(n) + G(n-1) = G(n) + G(n-1) + 2G(n) + G(n-1) = 3G(n) + 2G(n-1). Since n ≥ 2, we know that n-1 ≥ 1, and thus by part (c) we know G(n) ≥ G(n-1). Thus 3G(n) + 2G(n-1) ≤ 3G(n) + 2G(n) = 5G(n), as desired. As n was arbitrary, we have completed a generalization proof of ∀n: (n ≥ 2) → G(n+3) ≤ 5G(n).
First, f(0110) = 1 - f(011) = 1 - (1 + f(01)) = 1 - (1 + (1 + f(0))).
Since f(0) = 1 - f(λ) = 1, we have 1 - 3 = -2. If you
treated
the "-" operator as associative and left off the parentheses, you
probably got the wrong answer.
For the other one, f(01010) = 1 - f(0101) = 1 - (1 + f(010)) =
1 - (1 + (1 - f(01))). From above, f(01) = 2, so we get 1 - (1 +
(1 - 2) = 1.
public static int
f (string w)
to compute f(w) for any pseudo-Java binary
string w. Remember that unlike real Java String
objects,
pseudo-Java string
values are primitives. Use the
methods public static boolean isEmpty
, public
static char last
, and public static string
allButLast
as given in the book. Each of these three
methods takes a single argument of type string
.
There were lots of syntax errors, mostly people ignoring the
note about
public static int f (string w) {
if (isEmpty(w)) return 0;
if (last(w) == '0') return 1 - f(allButLast(w));
if (last(w) == '1') return 1 + f(allButLast(w));
throw new Exception ("f: invalid input string");}
string
values being primitive and
writing w.isEmpty( )
and so forth. Also, many
people wrote code that would not compile because the compiler
could not see a return
statement or exception on
every computation path. There were many ways to deal with the
case where w is non-empty and last(w)
is neither
'0'
nor '1'
-- since this will never
happen for valid input I don't care what you did, but you had to
do something. I took off only a point for either or both of
these errors. I didn't take off it the only error was
"0"
instead of '0'
, but I did take
off for just 0
.
We define P(w) to be "f(0w) = f(1w)". P(λ) says that f(0λ) = f(1λ), which means f(0) = f(1), and this is true because f(0) = 1 - f(λ) = 1 and f(1) = 1 + f(λ) = 1. So now let w be arbitrary, assume that P(w) is true, and we will prove both P(w0) and P(w1). P(w0) says "f(0w0) = f(1w0)", which reduces by the definition to 1 - f(0w) = 1 - f(1w), which is true because f(0w) = f(1w) by the IH. Similarly P(w1) reduces to 1 + f(0w) = 1 + f(1w), and this also follows from the IH.
The proof is easy once you find the right statement to prove, which
is that f(w) is odd if and only if the length of w is odd.
We can
prove this by induction for all strings, with P(w) being "f(w) and
|w| are both odd or both even". P(λ) is true because
f(λ) and |λ| are both 0 and thus both even. Assuming
that f(w) and |w| are both odd or both even, we note that f(w0) = 1
- f(w), f(w1) = 1 + f(w), and |w| all have the opposite parity from
f(w) and |w|, and thus have the same parity as each other.
You can use induction on odd numbers to prove that for any odd n,
for any w of length n, f(w) is odd. This is easy to prove by assuming
that f(w) is odd and calculating f(w00), f(w01), f(w10), and f(w11)
and showing that each of these numbers is odd. Many of you tried to
do this induction with the wrong P(w), trying to show that if |w| is
odd, f(w) is nonzero. But just knowing that f(w) ≠ 0 does
not tell you that f(w11) = f(w) + 2, for example, is also nonzero.
The reason this problem was extra credit is that you have to not only
prove something by induction but figure out the exact statement you
need to prove -- the stronger statement is easier to prove by
induction.
The list begins as {s}. Then s comes off, a, d, and e go on, and the list is {a, d, e}. Then a comes off, b goes on, and the list is {b, d, e}. Then b comes off, c and d go on, and the list is {c, d, d, e}. Then c comes off and g goes on. We do not stop yet because the algorithm says to wait until g comes off. The list is now {g, d, d, e}. Finally g comes off and we declare victory with a path s → a → b → c → g.
The list begins as {s}. First s comes off, and a, d, and e go on. Then a comes off, and b goes on making the list {d, e, b}. Then d comes off and f and g go on, making the list {e, b, f, g}. Then e comes off and f goes on again (it is not yet on the closed list) making the list {b, f, g, f}. Then b comes off and j goes on, making the list {g, f, c, j}. Finally g comes off and we declare victory. The path is s → d → g, as we put d on for its edge from s and g on for its edge from d.
The list begins as {s0}. We take s0 off and put on a1, d5, and e6. We take a1 off and put on b2, making the list {b2, d5, e6}. We take b2 off and put on c4 and d3, making the list {d3, c4, d5, e6}. We take d3 off and put on g7 and f4, making the list {c4, f4, d5, e6, g7}. We take off c4 (breaking the tie alphabetically) and put on another g7, making the list {f4, d5, e6, g7, g7}. We take off f4 and put on j5, making the list {d5, j5, e6, g7, g7}. We take off d5 and discard it because d is already on the closed list. We take off j5 and put on g6, making the list {e6, g6, g7, g7}. We take off e6 and put nothing on because f is already on the closed list. Finally we take g6 off and declare victory with the path s → a → b → d → f → j → g.
All edges in G have cost at least 1. So the cost of the cheapest path
from x to g is at least as great as the number of edges on that path,
which is at least as great as the smallest number of edges on any
path.
The definition of "admissible heuristic" requires that h(x) ≥ 0 and
h(x) ≤ d(x, g). We've shown the latter, and the former is true
because a path must have a non-negative number of edges.
The path returned by the A* search is the same path as
in uniform-cost search, in this case s → a → b → d
→ f → j → g.
The node e goes on the priority queue with priority 9, since its
distance from s is 6 and h(e) = 3. Since there is a path of cost 6
from s to g, and h(g) = 0, g will go on the priority queue with
priority 6, and come off before e does. In the uniform-cost
search, e and g both have priority 6 and e comes off first by the
alphabetical tiebreaker.
The A* search begins with {s2} on the priority queue,
takes off s2 and puts on a4, d6, and e9, takes off a4 and puts on
b4, takes off b4 and puts on c5 and d4, takes off d4 and puts on f6
and g7, takes off c5 and puts on g7, takes off f6 and puts on j6,
takes off j6 and puts on g6, and finally takes off g6 and declares victory.
Last modified 9 May 2012