CMSI 282
Homework #4

Read Chapters 6, 8, and 9 in the text.

This assignment consists of two Java projects, for which you will submit hardcopy printouts and check in sources to your CS repository. The repository should contain at least the following:

    /homework/cmsi282/src/main/java/edu/lmu/cs/yourloginname/algorithms/ArrayUtil.java
    /homework/cmsi282/src/main/java/edu/lmu/cs/yourloginname/algorithms/KirkmanSolver.java

This assignment must be ready on the last day of class, May 1, 2008. There can be no extensions for this assignment, because we are going to have a contest in class. I will check out each student's solutions for the subset summer from their CVS repository during class and run some unit tests on it. If the solution fails the tests, it will receive either a C or an F, depending on the code quality. For those that pass, the tests, we will run them and time them. The student with the fastest solution gets some extra credit. I will also race your solutions against my subset summer. If your solution is faster than mine, you get a lot of extra credit.

If I cannot at least check out your code from your repository and compile it without errors, you will receive and F. Students are strongly encouraged to ensure that I have access to your repository before May 1.

Here are the two problems

  1. Implement a class with a single method that takes in an array of positive integers A, and a non-negative value N, and determines whether some subset of the elements of A sum to N. The required specification:
    package edu.lmu.cs.____.algorithms
    
    public class ArrayUtil {
        private ArrayUtil() {}
    
        public static boolean hasSubsetSum(int[] a, int n) {
            // Implement me
        }
    }
    

    Here is a tester:

    package edu.lmu.cs.algorithms;
    
    import static edu.lmu.cs.algorithms.ArrayUtil.hasSubsetSum;
    import static org.junit.Assert.assertFalse;
    import static org.junit.Assert.assertTrue;
    
    import org.junit.AfterClass;
    import org.junit.BeforeClass;
    import org.junit.Test;
    
    /**
     * Unit test for my <code>hasSubsetSum</code> utility.
     */
    public class ArrayUtilTest {
    
        private static int[] A01 = {};
        private static int[] A02 = {5};
        private static int[] A03 = {535499222};
        private static int[] A04 = {2, 5, 4, 99};
        private static int[] A05 = {5, 3, 9, -1};
        private static int[] A06 = {50000, 50000, 50000, 1};
        private static int[] A07 = {7, 13, 12, 16, 45, 4, 4, 9};
        private static int[] A08 = {12, 99, 6, 99, 10, 99, 15, 3};
    
        // Large array with values in the hundreds
        private static int[] A10;
    
        // Large array with values in the single digits
        private static int[] A11;
    
        // Large array with values in the tens of thousands
        private static int[] A12;
    
        @BeforeClass
        public static void initialize() {
            System.out.println("Generating large test arrays...");
            A10 = new int[10000];
            for (int i = 0; i < A10.length; i++) {
                A10[i] = (i * 703) % 631 + 1;
            }
            A11 = new int[10000];
            for (int i = 0; i < A11.length; i++) {
                A11[i] = (i * 703) % 6 + 1;
            }
            A12 = new int[10000];
            for (int i = 0; i < A12.length; i++) {
                A12[i] = (i * 703) % 999999 + 1;
            }
            System.out.println("Beginning tests...");
        }
    
        @AfterClass
        public static void done() {
            System.out.println("Finished with tests");
        }
    
        @Test
        public void testEmpty() {
            assertTrue(hasSubsetSum(A01, 0));
            assertFalse(hasSubsetSum(A01, 1));
            assertFalse(hasSubsetSum(A01, 2));
            assertFalse(hasSubsetSum(A01, 1978342888));
            assertFalse(hasSubsetSum(A01, Integer.MAX_VALUE));
        }
    
        @Test
        public void testSingleton() {
            assertTrue(hasSubsetSum(A02, 0));
            assertTrue(hasSubsetSum(A02, 5));
            assertFalse(hasSubsetSum(A02, 2100832388));
            assertTrue(hasSubsetSum(A03, 0));
            assertTrue(hasSubsetSum(A03, 535499222));
            assertFalse(hasSubsetSum(A03, 2100832388));
        }
    
        @Test
        public void testSmallArrays() {
            // A04 = [2, 5, 4, 99]
            assertTrue(hasSubsetSum(A04, 0));
            assertTrue(hasSubsetSum(A04, 2));
            assertTrue(hasSubsetSum(A04, 4));
            assertTrue(hasSubsetSum(A04, 5));
            assertTrue(hasSubsetSum(A04, 6));
            assertTrue(hasSubsetSum(A04, 7));
            assertTrue(hasSubsetSum(A04, 9));
            assertTrue(hasSubsetSum(A04, 11));
            assertTrue(hasSubsetSum(A04, 99));
            assertTrue(hasSubsetSum(A04, 101));
            assertTrue(hasSubsetSum(A04, 103));
            assertTrue(hasSubsetSum(A04, 104));
            assertTrue(hasSubsetSum(A04, 105));
            assertTrue(hasSubsetSum(A04, 106));
            assertTrue(hasSubsetSum(A04, 108));
            assertTrue(hasSubsetSum(A04, 110));
            assertFalse(hasSubsetSum(A04, 1));
            assertFalse(hasSubsetSum(A04, 3));
            assertFalse(hasSubsetSum(A04, 8));
            assertFalse(hasSubsetSum(A04, 10));
            assertFalse(hasSubsetSum(A04, 12));
            assertFalse(hasSubsetSum(A04, 13));
            assertFalse(hasSubsetSum(A04, 46));
            assertFalse(hasSubsetSum(A04, 29));
            assertFalse(hasSubsetSum(A04, 100));
            assertFalse(hasSubsetSum(A04, 102));
            assertFalse(hasSubsetSum(A04, 107));
            assertFalse(hasSubsetSum(A04, 109));
            assertTrue(hasSubsetSum(A08, 16));
            assertFalse(hasSubsetSum(A08, 345366916));
    
        }
    
        @Test
        public void testLargeArraysWithSmallValues() {
            assertFalse(hasSubsetSum(A11, 70000));
            assertTrue(hasSubsetSum(A11, 10));
        }
    
        @Test
        public void testLargeArraysWithSmallTargetSum() {
            assertTrue(hasSubsetSum(A10, 1));
            assertTrue(hasSubsetSum(A10, 5));
            assertTrue(hasSubsetSum(A10, 7));
            assertTrue(hasSubsetSum(A10, 20));
            assertTrue(hasSubsetSum(A11, 1));
            assertTrue(hasSubsetSum(A11, 5));
            assertTrue(hasSubsetSum(A11, 7));
            assertTrue(hasSubsetSum(A11, 20));
            hasSubsetSum(A12, 89);
            hasSubsetSum(A12, 789);
            hasSubsetSum(A12, 29);
            hasSubsetSum(A12, 1189);
            hasSubsetSum(A12, 3);
        }
    
        @Test
        public void testNasties() {
            // No assertions here because the values are random.
            // Just here for timing.
            hasSubsetSum(A10, 34453);
            hasSubsetSum(A10, 343543556);
            // EVIL: hasSubsetSum(A12, 343543556);
        }
    
        @Test(expected=IllegalArgumentException.class)
        public void testNegativeSum() {
            assertFalse(hasSubsetSum(A02, -1));
            assertFalse(hasSubsetSum(A02, -1436));
            assertFalse(hasSubsetSum(A10, -5));
        }
    
        @Test(expected=IllegalArgumentException.class)
        public void testNegativesInArray() {
            hasSubsetSum(A05, 100);
        }
    }
    
  2. Write a Java application that finds (NOT "prints a hardcoded solution") a solution to the famous Kirkman's Schoolgirl Problem. You only need to find one solution, not all of them. Solve the version with the fifteen kids that walk in five rows of three each.