Question text is in black, solutions in blue.
Q1: 10 points Q2: 15 points Q3: 15+10 points Q4: 30 points Q5: 30 points Total: 100+10 points
Definitions and Other Notes:
N is the set of naturals, {0, 1, 2, 3,...}.
Question 3 uses an inductively defined function from {a, b}* to N. We define f(λ) = 0, and for any string w we define f(wa) = f(w) + 1 and f(wb) = 2f(w).
Question 4 uses the following inductive definition of "set expression":
int
values.
Question 4 assumes that we have defined a real-Java class
IntSet
whose objects are sets of int
values. The only method of this class that you will need is
public boolean isIn (int x)
, which returns
true
if and only if the int
value
x
is in the calling set. Note that Question 4 will
ask you to write a different method isIn
, for
the SetExpression
class.
We also have the following real-Java class for set expressions:
public class SetExpression {
public static final int UNION = 1;
public static final int INTERSECTION = 2;
public static final int COMPLEMENT = 3;
boolean isLeaf;
IntSet leafValue;
SetExpression left, right;
int op;
// usual constructors, getters, and setters
Question 5 uses the following labeled undirected graph:
[a] ---1--- [s] ---1--- [f]
| | |
3 6 9
| | |
[b] ---1--- [d] ---1--- [g]
| | |
3 6 9
| | |
[c] ---1--- [e] ---1--- [h]
The Fibonacci numbers are a sequence of natural numbers defined by the rules F(0) = 0, F(1) = 1, and for any n with n ≥ 1, F(n+1) = F(n) + F(n-1). The sequence begins 0, 1, 1, 2, 3, 5, 8, 13,...
The one's complement of a binary string w is another binary string of the same length as w, with a 0 wherever w has a 1 and a 1 wherever w has a 0. For example, the one's complement of 01001 is 10110.
An undirected cycle in an undirected graph is a path from some node x to itself that never reuses an edge. It must have three or more edges. (I insisted on a definition that ruled out paths from some x to some y and then back along the same route, for example.)
A heuristic for an A* search is a function that assigns each node x of the graph a non-negative real number, which is a lower bound on the best-path distance from x to a goal node. It is used to determine the order in which entries come off of the priority queue. (I insisted on your saying that h(x) was between 0 and d(x, g).)
A bipartite graph is one whose nodes can be partitioned into two sets, such that every edge has one endpoint in each set. Equivalently, it is an undirected graph with no cycles of odd length. Also equivalently, it is a graph whose nodes may be two-colored so that no edge connects nodes of the same color.
Ordinary induction on k, starting with k = 3, where P(k) is the
statement "R(x1, xk)".
Base Case: We want to prove R(x1, x3).
We know R(x1, x2) and R(x2,
x3) from the assumptions. So R(x1,
x3) follows by transitivity.
Inductive Hypothesis: R(x1, xk)
Inductive Step: We want to prove P(k+1) which is
R(x1, xk+1). We have R(x1,
xk) from the IH and R(xk, xk+1)
from the assumptions. So our desired statement follows by
transitivity.
f(aabb) = 2f(aab) = 2(2f(aa)) = 4(f(a) + 1) = 4(f(λ) + 1 + 1) =
4(0 + 2) = 8.
f(baba) = f(bab) + 1 = 2f(ba) + 1 = 2(f(b) + 1) + 1 =
2(2f(λ) + 1) + 1 = 2(1) + 1 = 3.
f(abba) = f(abb) + 1 = 2f(ab) + 1 = 2(2f(a)) + 1 =
2(2(f(λ) + 1)) + 1 = 4(1) + 1 = 5.
Ordinary induction on all naturals. P(n) is "∃w:f(w) = n".
Base case: n = 0. We must prove that some string w exists
with f(w) = 0. The definition tells us that λ is such a
string.
Inductive Hypothesis: ∃w: f(w) = n
Inductive Step: We must prove ∃v:f(v) = n + 1. Using the
IH, we have w such that f(w) = n. Letting v = wa, the
definition tells us that f(v) = f(wa) = f(w) + 1 = n + 1.
Strong induction on all naturals. P(n) is "&exists;w: w satisfies
(1) and (2)". We define Q(n) to be "∀i: (i ≤n) →
P(i)".
Base case: Let w = λ, then w does not have two a's in
a row and f(w) = 0.
Strong inductive hypothesis: For any i with i ≤ n, there
exists a string w such that w does not have two a's in a row and
f(w) = i.
Inductive step: We must prove that there exists a string v
such that v does not have two a's in a row and f(v) = n + 1.
Case 1: n + 1 is odd. Let k = n/2 so that n + 1 = 2k + 1.
By the SIH, let w be a string without two a's in a row such that
f(w) = k. Then let v = wba, so that f(v) = 2f(w) + 1 = 2k + 1.
We know that v
does not have two a's in a row because w doesn't, and the new a is
separated from any other a's.
Case 2: n + 1 is even. Let k = (n + 1)/2, so that 2k = n + 1. By
the SIH, let w be a string with no two a's in a row such that f(w) =
k. Then let v = wb, so that f(v) = 2f(w) = 2k = n + 1. We know that
v does not have two a's in a row because w doesn't and v has no new a's.
IntSet
and
SetExpression
, all defined above.
C-bar is the set of all ints except 2, 7, and 9. B ∪ C-bar is the set of all ints except 2 and 9. (Many of you interpreted ∪ as intersection here for some reason.) Then A ∩ (B ∪ C-bar) = {3, 7} as only 2 fails to be in the other set.
public boolean
isIn (int x)
for the SetExpression
class.
It should return true
if and only if the
int
value x
is in the set denoted by
the calling SetExpression
object.
This assumes that the input is correctly formed, with
public boolean isIn (int x) {
if (isLeaf) return leafValue.isIn(x);
if (op = UNION) return left.isIn(x) || right.isIn(x);
if (op = INTERSECTION) return left.isIn(x) && right.isIn(x);
else return !left.isIn(x);}
op
equal
to one of the three given values, and that the argument of a
COMPLEMENT operation is stored in left
. Many of you
confused the int value x with leafValue (which is a set, not an
int) or with the op values (which are ints only because I learned
Java before the invention of the enum feature).
Induction on all set expressions E, where P(E) says "Our method
returns a boolean that tells whether x is in the set denoted by E".
Base case: E is a leaf, containing an Inductive hypothesis: P(F) and P(G) are true for any set
expressions F and G we combine with an operation to get E.
Inductive step: We must prove P(E), and there are three cases
depending on the IntSet
object in its leaf value. We call the isIn
method
of the IntSet
class, which we assume returns a boolean
telling whether x is in the set.
op
value for E. If op = UNION, we
recursively determine whether x is in the sets for F or G, and by the
IH these calls give correct answers. Then we return true if and only
if at least one of these calls return true. If op = INTERSECTION, we
make the same recursive calls and return true if and only if both of
them return true. Finally, if op = COMPLEMENT, we reach the else
clause of the code, compute whether x is in the set for F by a
recursive
call (which returns a correct answer by the IH), and return the
negation of this answer. In each case our output matches the intended
meaning of the operator.
The stack starts with s. We process s and push its neighbors, making
the stack {a, d, f} starting from the top. We pop a and push its
only neighbor b, getting {b, d, f}. We pop b and push its
neighbors c and d, getting {c, d, d, f}. (We don't push a
because it is on the closed list, but d is not on the closed
list.)
We next pop c and push its neighbor e to get {e, d, d, f}. We
pop e and push its neighbors d and h to get {d, h, d, d, f}. We
pop d and push g, getting {g, h, d, d, f}. We pop g and declare
victory.
The DFS tree is a single path s-a-b-c-e-d-g. The edges from s
to d and from s to f are not on the tree as we never closed the
corresponding node entries -- they remained on the stack at the end.
The queue starts with s. We dequeue s and enqueue a, d, and f to get
{a, d, f}. We dequeue a and enqueue b to get {d, f, b}. We
dequeue d and enqueue e and g to get {f, b, e, g}. We dequeue f
and enqueue g to get {b, e, g, g}. We dequeue b and enqueue c to
get {e, g, g, c}. We dequeue e and enqueue h to get {g, g, c,
h}. Finally we dequeue g and declare victory.
The path we found is s-d-g because we found d from s and g
from d. The BFS tree contains only the nodes that we dequeued: s
is the root and has children a, d, and f; a has only child b, d
has children e and g (with a non-tree edge to b), and f has no
children.
We begin with (s,0) on the priority queue. We dequeue (s, 0) and enqueue (a,1), (d,6), and (f,1). We dequeue (a,1) (using the alphabetical tie-breaker) and enqueue (b,4). We dequeue (f,1) and enqueue (g,10). The queue now holds (b,4), (d,6), and (g,10). We dequeue (b,4) and enqueue (c,7) and (d,5). We dequeue (d,5) and enqueue (e,11) and (g,6). We next might dequeue either (d,6) or (g,6), since these two nodes were not enqueued at the same time so the tie-breaker does not apply. If we dequeue (d,6) we just discard it as d is on the closed list. Once we dequeue (g,6) we declare victory, finding the path s-a-b-d-g of length 6.
Last modified 13 November 2013