LMU ☀️ CMSI 2130
ALGORITHMS
HOMEWORK #4 PARTIAL ANSWERS
  1. Dasgupta 3.8 — 10-7-4 Water Jug Problem
    # 10-7-4 Water Jug Problem
    
    # Get 2 units of water in the 7-container or the 4-container
    
    # Starting state is (0,7,4)
    # Operations are F10, F7, F4, T107, T104, T710, T74, T410, T47
    # Goal states are (x,2,z) and (x,y,2)
    
    operations = {
        'F10'  : lambda x, y, z: [10, y, z],
        'F7'   : lambda x, y, z: [x, 7, z],
        'F4'   : lambda x, y, z: [x, y, 4],
        'T107' : lambda x, y, z: [0, y+x, z] if y+x<=7 else [x-(7-y), 7, z],
        'T104' : lambda x, y, z: [0, y, z+x] if z+x<=4 else [x-(4-z), y, 4],
        'T710' : lambda x, y, z: [x+y, 0, z] if x+y<=10 else [10, y-(10-x), z],
        'T74'  : lambda x, y, z: [x, 0, z+y] if z+y<=4 else [x, y-(4-z), 4],
        'T410' : lambda x, y, z: [x+z, y, 0] if x+z<=10 else [10, y, z-(10-x)],
        'T47'  : lambda x, y, z: [x, y+z, 0] if y+z<=7 else [x, 7, z-(7-y)],
    }
    
    def dfs(state, visited, solution):
        solution.append(state)
        if state[1] == 2 or state[2] == 2:
            return True
        for (op, transition) in operations.items():
            next = transition(*state)
            if str(next) not in visited and dfs(next, visited|{str(next)}, solution):
                return True
        solution.pop()
        return False
    
    
    solution = []
    if dfs([0,7,4], set(), solution):
        print(solution)
    
  2. Dasgupta problem 4.1
    A   B   C   D   E   F   G   H
    -----------------------------
    0   -   -   -   -   -   -   -
        1   -   -   4   8   -   -
            3   -   4   7   7   -
                4   4   7   5   -
                    4   7   5   8
                        6       6
                                6
    
             1         2         1
        A-------->B-------->C-------->D
        |                   |
        | 4                 | 2
        |                   |
        v              1    v    1
        E         F<--------G-------->H
    
  3. Dasgupta problem 4.2
    $ python3 bellman_ford.py
        S    A    B    C    D    E    F    G    H    I
        0    -    -    -    -    -    -    -    -    -
        0    7    -    6    -    6    5    -    -    -
        0    7   11    5    8    6    4    -    9    -
        0    7   11    5    7    6    4    9    7    -
        0    7   11    5    7    6    4    8    7    8
        0    7   11    5    7    6    4    8    7    7
        0    7   11    5    7    6    4    8    7    7
        0    7   11    5    7    6    4    8    7    7
        0    7   11    5    7    6    4    8    7    7
        0    7   11    5    7    6    4    8    7    7
        0    7   11    5    7    6    4    8    7    7
    
  4. Dasgupta Problem 4.18 — Just modify Dijkstra's algoritm so that priority queue entries contain tuples of the form $(predecessor, distanceFromSource, hopsFromSource)$ and adjust your comparator to consider hops whenever there are ties for the distance.
  5. Prim's MST Algorithm, with input/output as a string.
  6. Subset Sum, for positive integers.

    subsetsums.py
    import unittest
    
    
    # This script illustrates subset summing using dynamic programming in Python.
    #
    # It turns out there is a way to do this in Python by brute-force using
    # the built-in combinations function from itertools. It is very cool, and
    # I thought you might love to see it. It works like this:
    #
    # from itertools import chain, combinations
    #
    # def has_subset_sum(s, k):
    #     for subset in chain.from_iterable(combinations(s, r) for r in range(len(s)+1)):
    #         if sum(subset) == k:
    #             return True
    #     return False
    
    
    def has_subset_sum(s, k):
        if len(s) == 0:
            return k == 0
    
        low = sum(x for x in s if x < 0)
        high = sum(x for x in s if x > 0)
    
        prev_table = [False] * (high - low +1)
        for value in s:
            table = prev_table[:]
            for test_value in range(low, high+1):
                index = test_value - low
                if prev_table[index] or \
                        value == test_value or \
                        (0 < index-value < len(table) and prev_table[index-value]):
                    table[index] = True
                    if test_value == k:
                        return True
            prev_table = table
        return False
    
    class SubsetSumTestCase(unittest.TestCase):
        def test_it(self):
            self.assertTrue(has_subset_sum(set([]), 0))
            self.assertTrue(has_subset_sum({4}, 4))
            self.assertFalse(has_subset_sum({4}, 8))
            self.assertTrue(has_subset_sum({4, -1}, 4))
            self.assertTrue(has_subset_sum({4, -1}, 3))
            self.assertTrue(has_subset_sum({4, -1}, -1))
            self.assertFalse(has_subset_sum({4, -1}, 40))
            self.assertFalse(has_subset_sum({4, -1}, -80))
    
        def test_a_specific_example(self):
            s = {-3, -4, 1, 4}
            for k in (-7, -6, -4, -3, -2, 0, 1, 2, 4, 5):
                self.assertTrue(has_subset_sum(s, k))
            for k in (-10, -9, -8, -5, -1, 3, 6, 7, 8, 9):
                self.assertFalse(has_subset_sum(s, k))
    
    unittest.main()
    
  7. Coin Changing.