Assignment 13 - COP 3530, Fall 2007

Please read the assignment submission rules and the academic dishonesty page before you start work on this assignment. Failure to comply by these rules will cost a significant percentage of your assignment grade.


Make sure your classes are in the package dataStructures. If you do not understand what packages are you can read this tutorial, if you have trouble with the classpath settings you could try reading this tutorial.

In this assignment, you *ARE* allowed to use any classes from the dataStructures or the java.util packages.





Problem 1 [0-1-2 Knapsack]

a) In the 0-1 Knapsack problem, given n items with weights w(1), ..., w(n) and values v(1),...,v(n) one chooses k items such that all their weights are less than (or equal to) c so that the sum of the values of those items are maximized. The 0-1 part means that you either take the item or you don't, but you cannot take the item twice.
In this problem, we still try to maximize the values of the items which have total weight of less than c, but this time it is possible to take an item twice. But when taking the item the second time, the value will be decreased by half, i.e. if item m is already taken so that it takes w(m) weight and adds v(m) value, the second time we take it it still adds w(m) weight, but the value this time will be v(m) / 2.
Solve this problem using a greedy approach (your solutions need not find the optimal solution), by modifying the GreedyKnapsack class in the code.applications package by adding the method
public static double greedyKnapsack012(double[] p, double[] w, 
double c, int[] x )


Your solution should have a worst case running time of O(nlogn), where n is the number of different items.
 
b) Generalize the previous problem, so that each item m can be taken any number of times, but taking it the kth time will only add v(m)/k value to the sum. So the second time we take m, it will add v(m)/2 value, the third time will add v(m)/3 value etc. Implement a greedy solution to this problem as:

public static double greedyKnapsack01N(double[] p, double[] w, 
double c, int[] x )

Your solution should have a worst case running time of O(nlogn + mn), where n is the number of different items and m is the number of (not necessarily distinct) items in your solution.

c)
What are your worst case running times? Can you improve your worst-case running time for part (b)? If yes, how? If no, why not?

The main method should look like:
 public static void main(String [] args)
{
double [] p = {0, 16, 3, 5, 4, 7};
double [] w = {0, 2, 2, 6, 5, 4};
int [] x = new int [6];
int n = 5;
double c = 10;
System.out.print("Greedy value is "); //Should print 34.0
System.out.println(greedyKnapsack012(p, w, c, x));
System.out.print("x vector is ");
for (int i = 1; i <= n; i++)
System.out.print(x[i] + " "); //Should print 2 1 0 0 1

x = new int [6];
System.out.print("Greedy value is "); //Should print 36.533
System.out.println(greedyKnapsack01N(p, w, c, x));
System.out.print("x vector is ");
for (int i = 1; i <= n; i++)
System.out.print(x[i] + " "); //Should print 5 0 0 0 0
}

Note:
1) The reason we are modifying the class rather than extending it is that some necessary parts of the class are made private, so a subclass will not be able to use them.
2) This class should be in the "applications" package, NOT "dataStructures" package.

Extra Credit Problem [8 Puzzle]

The 8-puzzle is a sliding puzzle, which has a 3 by 3 grid of squares numbered 1 through 8 -- the ninth square is missing. The missing square makes it possible to move a neighboring square to its position. The object of the puzzle is to keep moving the squares and get the final position which has 1, 2 and 3 in the upper row (in order), 4,5,6 in the middle row (in order) and 7,8 in the bottom row - the bottom-right square being empty.
For a more detailed explanation, see the 15 Puzzle page on Wikipedia. The 15 puzzle is the same puzzle, only played on a 4x4 grid, rather than 3x3.

Given the template below, implement the method public void solvePuzzle() and the constructor public EightPuzzle(int[] startPosition)
Running the main method should give an output similar to this output. (It might be different if a different search strategy is used)

Note: You *ARE* allowed to use any classes from the dataStructures or the java.util packages.
package dataStructures;

public class EightPuzzle {

Node startingNode;
Node finish = new Node(new int[] {1,2,3,4,5,6,7,8,0}, null);

//DATA MEMBERS GO HERE

public EightPuzzle(int[] startPosition) {

startingNode = new Node(startPosition, null);

//YOUR CODE HERE
}

public void solvePuzzle() {

//YOUR CODE HERE

}

//HELPER METHODS HERE

public static void main(String[] args) {

EightPuzzle eightPuzzle =
new EightPuzzle(new int[] {1,6,3,8,5,4,0,2,7});
eightPuzzle.solvePuzzle();

}

}


class Node {

static int NINE = 9;

private int[] state; //holds the state array,
//0 is top left, 1 one to the right and so on

Node previousNode; //holds a pointer to the previous node,
//to recreate the solution path

Node(int[] state, Node prev) {
this.state = state;
previousNode = prev;
}

/* returns an integer that will be used as a key for this state
this will be used for the Hashtable
or AVLtree holding the visited states

in effect this is a basic hash function */
int key() {
int key = 0;
for (int i = 0; i < NINE; i++) {
key += state[i] * Math.pow(10, i);
}

return key;
}

//returns the position of 0 - the empty tile
private int emptySpot() {
for (int i = 0; i < NINE; i++ )
if (state[i] == 0) return i;
return -1;
}

//swaps the two positions in the state array,
//and returns the resulting Node

private Node swap(int pos1, int pos2) {
int[] array = new int[NINE];
for (int i = 0; i < NINE; i++) {
if (i == pos1) array[i] = state[pos2];
else if (i == pos2) array[i] = state[pos1];
else array[i] = state[i];
}
return new Node(array, this);
}

//returns the node after moving in the given direction
//0 is up, 1 is right, 2 is down, 3 is left
//the directions are the movement of the empty spot, not the tiles!
Node move(int direction) {
int emptySpot = emptySpot();
if (direction == 0) {
if (emptySpot < 3) return this;
else return swap(emptySpot, emptySpot - 3);
}
else if (direction == 1) {
if (emptySpot % 3 == 2) return this;
else return swap(emptySpot, emptySpot + 1);
}
else if (direction == 2) {
if (emptySpot > 5) return this;
else return swap(emptySpot, emptySpot + 3);
}
else if (direction == 3) {
if (emptySpot % 3 == 0) return this;
else return swap(emptySpot, emptySpot - 1);
}
}

public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("--------\n");
sb.append("| "+ state[0] + " " + state[1] + " "
+ state[2] + "|\n");
sb.append("| "+ state[3] + " " + state[4] + " "
+ state[5] + "|\n");
sb.append("| "+ state[6] + " " + state[7] + " "
+ state[8] + "|\n");
sb.append("--------\n");
return sb.toString();
}
}