Wall Street Monopoly

I was working on Wall Street Monopoly at UCF Local Programming Contest in 2012. My professor explained this is Matrix Chain Multiplication, but it took me a while to get how to apply Matrix Chain Multiplication to this problem. So here is a little note for myself.

Wiki’s pseudocode doesn’t save the generated matrix dimension from multiplication, and I didn’t get how p[] computes the cost of multiplication, so I created 3D array to save the result of multiplication of matrix.

Here is my basic code for Matrix Chain Multiplication

// Get input data
// n is how many matrixes we have
// matrix is a global variable that stores row and col of each matrix
matrix = new int[n][2];
for (int i = 0; i < n; i++) {
	matrix[i] = new int[]{scanner.nextInt(), scanner.nextInt()};
}

// matrixDimension is a global variable that stores the dimension of multiplied matrix from i through j
matrixDimension = new int[n][n][2];
for (int i = 0; i < n; i++) {
	for (int j = i; j < n; j++) {
		if (i == j) {
			// if i == j, store its dimension
			matrixDimension[i][j] = matrix[i];
		} else {
			// If it is multiplied matrix, stores the row of the first matrix and column of the second matrix
			matrixDimension[i][j] = new int[]{matrixDimension[i][j - 1][0], matrix[j][1]};
		}
	}
}

Then, to calculate the minimum multiplication cost, I do it recursively and save the result of calculation in 2D array memo

// This is in main function
System.out.println(solve(0, n - 1));

// The basic idea for this function is well explained in the section of [A Dynamic Programming Algorithm](https://en.wikipedia.org/wiki/Matrix_chain_multiplication#A_Dynamic_Programming_Algorithm)
public static int solve(int start, int end) {
	// If start and end is the same, return 0 since no multiplication occurs
	if (start == end) {
		return 0;
	}
	
	// If we already calculated this once, return saved value
	if (memo[start][end] != -1) {
		return memo[start][end];
	}
	
	int answer = Integer.MAX_VALUE;
	for (int i = start; i < end; i++) {
		// Partition matrix from i to k and k to j.
		// This reminds me merge sort
		int a = solve(start, i) + solve(i + 1, end) + matrixDimension[start][i][0] * matrixDimension[start][i][1] * matrixDimension[i + 1][end][1];
		answer = Math.min(answer, a);
	}
	memo[start][end] = answer;
	return answer;
}

So here is my core code for Matrix Chain Multiplication. I changed this code to this. The change I made is how I set up matrixDimension and the value I add in solve function.

// Read data is the same

// This function has changed
public static void setDimension() {
	for (int i = 0; i < n; i++) {
		for (int j = i; j < n; j++) {
			if (i == j) {
				dimension[i][j] = blocks[i];
			} else {
				// I changed here.
				// For x, I add x of both matrix
				int x = dimension[i][j - 1][0] + blocks[j][0];
				// For y, I keep the bigger value
				int y = Math.max(dimension[i][j - 1][1], blocks[j][1]);
				// And use them to set multiplied or fused matrix dimension
				dimension[i][j] = new int[]{x, y};
			}
		}
	}
}

// 
public static long solve(int start, int end) {
	if (start == end) {
		return 0;
	}
	if (memo[start][end] != -1) {
		return memo[start][end];
	}
	
	long answer = Long.MAX_VALUE;
	for (int i = start; i < end; i++) {
		// The value I add here has been changed to follow the problem.
		long a = solve(start, i) + solve(i + 1, end) + 100 * Math.min(dimension[start][i][0], dimension[start][i][1]) * Math.min(dimension[i + 1][end][0], dimension[i + 1][end][1]);
		answer = Math.min(answer, a);
	}
	memo[start][end] = answer;
	return answer;
}

Here is all my change I made! Summarixing this as a document helps me to grasp what I did. Hope this helps future programmers!