Exercises

8.1.3

Homework.

8.1.5

Homework.

8.1.6

Hints

  • Explain why is the formulation $F(n) = F(n-1) + p_1$ is wrong. Derive a counter example.
  • The optimal solution may be $F(n) = p_n$. Modify it so that it is in terms of $F(k)$ for some $k < n$.
  • Generalize.

Solution

Recursive formulation. \begin{aligned} F(0) &= 0 \\ F(n) &= \underset{1 \leq j \leq n}{\max} {p_j + F(n-j) } \end{aligned}

Algorithm.

    # input: Length n, and values of pieces of length i, P[i]
    # output: Maximum value of all possible cuts on a rod of length n
    def dynamicRodCut(n, P[0..n])

        # a rod of length zero contributes nothing to revenue
        P[0] = 0

        # Initialize an array of size n
        F = [] * (n+1)

        # Set the base case
        F[0] = 0

        # Compute bottom-up F[i]
        for i in 1..n

            maxVal = 0

            # Compute the maximum among all js
            for j in 0..i
                # call memoized subinstances
                # update if found a greater value
                maxVal = max( maxVal, P[j] + F(i-j) )

            # memoize
            F[i] = maxVal

        # return max value of cuts, on given length n
        return F[n]

Complexity. Time is $1 + \dots + n = n(n+1)/2$. Additional space is $n+1$.

8.2.2

Homework.

8.2.3

Homework.

8.2.5

Hints

  • Recall for the algorithm given in the book, at each step, either we take or leave the ith item.
  • For our case what if we at each step, either leave all items, or take 1st item, or take 2nd item, .., or nth item. Modify the formulation.

Solution

Recursive Formulation. \begin{aligned} F(W) &= 0 \qquad &\text{if } W < w_j, ; 1 \leq j \leq n \\ F(W) &= \underset{j: W \geq w_j}{\max} F(W - w_j) + v_j &\text{otherwise} \end{aligned}

Algorithm

    # memory function
    # input: i indicating selecting a multiset of item 1, item 2, .., item i
             j capacity
    # output: optimal value of a feasible multiset from item 1, item 2, .., item i
    def MFKnapsack(i, j, weight, value, F)
        
        # only if not memoized, compute and cache it
        if F[i,j] < 0

            # find the maximum value among all cases
            # item i added 0, 1, 2, .. times constrained by capacity
            count = 0
            while (count * weight[i]) < j
                maxVal = max( 
                            maxVal, 
                            (count * value[i]) + MFKnapsack( i-1, j - (count * weight[i]) )                     
                        )
            
            # memoize
            F[i,j] = maxVal

        return F[i,j]

    # input: weight of ith item, value of ith item, total capacity W
    # output: max value of a multiset of all given n items
    #         constrained by capacity W
    def dynamicKnapsack(weight[1..n], value[1..n], W)

        # memoization table
        # all cells -1, indicating no value is computed
        F[0..n, 0..W] = -1
        # except row 0 and column 0, values are 0, by definition of base case
        for i in 0..n, F[i,0] = 0
        for i in 0..W, F[0,i] = 0

        # compute memoization table F, and read F[n, W]
        sol = MFKnapsack(n, W, weight, value, F)

        # problem solution is F[n, W]
        return sol

8.3.4

Homework.

8.3.8

Hints.

  • Recall you have table $R$, where $R[i,j]$ contains the root of the tree of nodes $i, \dots, j$.
  • Recall how the optimal solution of knapsack was constructed.

Solution.

    # global variables: table R of roots indices
                        keys A
    # input: root node of a tree, and indices i and j of keys covered
    # output: None. Tree is modified so the root points to its children
    # initialize with i = 1 and j = n
    # def optimalBST(root, i, j)

        # base case
        if root = NULL
            return

        # index of the root of subtree of keys A_i, .., A_j
        k = R[i,j]

        # left child
        root.left = A[ R[i, k-1] ]
        # right child
        root.right = A[ R[k+1, j] ]

        # Recursively, Call the child
        optimalBST(root.left, i, k-1)
        optimalBST(root.right, k+1, j)

P.S. Anything by Donald Knuth is worthwhile studying, however for our pragmatic purposes we omit the analysis bounding $\mathcal{O}(n^2)$.