Tag Archive for 'path'

Project Euler : Count Integral Shortest Paths In All Cuboid Smaller Than Certain Dimension

Problem 86 of Project Euler is the next problem I took up. Given a cuboid with integral dimensions, the shortest distance for an ant to crawl from one corner to diagonally opposite corner need not be an integral number. The problem statement required one to consider all the possible cuboid up to a maximum size of M x M x M and report the number of cuboid that had integral value for the shortest path.

The question has a huge hint hidden within its wording. It goes on to provide two examples – for M = 99 the count is 1975 and for M  = 100 the count is 2060! Solve the problem incrementally. This problem can be disintegrated into 3 smaller problems.

Firstly, we need to know the calculation of shortest path in a cuboid as an ant would crawl. To do this, explode the 3D figure into a 2D figure keeping track of the corners. It’s a pretty simple matter to calculate the distance now. There’s one thing to be remembered though – the explosion can be done in 3 different ways. So we have potentially 3 candidates for the shortest path.

Given the dimension as a X b X c, the squared distance is one of (a+b)^{2} + c^{2}(b+c)^{2} + a^{2} or (c+a)^{2} + b^{2}. We shall see later that in our case we do not need to perform 3 calculations as the choice becomes quite obvious.

Next  we tackle the problem of induction. Say we know that the count for the problem size  M x M x M is some p. How do we calculate the value for the size (M+1) x (M+1) x (M+1)? If you were to imagine two cuboid of dimensions M and (M+1) and enumerate all the cuboid not covered by the one of dimension M, you would find them to be of the form:

i X j X (M+1)

where i = 1 to M + 1

and j = i to M + 1

There lies our solution! We setup a nested for loop and calculate the shortest distances for each of these extra cuboid. It should now be pretty obvious to notice that for the computation of shortest distance we only need to consider the case (i+j)^{2} + (M+1)^{2}. Thus we can go from M to M+1.

I hope you have noticed some redundancy in the above loop setup. Every time we calculate (i+j). Consider the two cases:

i = 1, j = 3

i = 2, j = 2

In both these cases the value of (i+j) is the same. We are unnecessarily computing values already computed. Being a little cleverer we can improve the current O(n^{2}) to O(n).

Instead of using a nested loop, we use a single for-loop from the range of 2 to 2*(M+1) as those are the range for the sum of i and j. But this introduces another problem. Say for a particular sum we get that the shortest path is an integer. We need to know the number of ways in which the sum can be decomposed into i and j. I setup a single line function to calculate this value and I was done!

The code ran in 258ms on my Lenovo T410 laptop. Below is my function to move from M to M+1. To solve the Project Euler problem, I just needed to call this function in a loop, always updating the memoized value.

 

    /**
     * Count the number of integral shortest paths in all cuboids upto a size of size X size X size
     *
     * @param size the maximum dimensions of the cuboid
     * @param memoizedValue the value for a cuboid with max dimension size - 1
     * @return the value for a cuboid of max dimension size X size X size
     */
    public int countIntegralShortDistances(int size, int memoizedValue) {
        double sizeSquared = Math.pow(size, 2);
        for (int i = 2; i <= 2 * size; i++)
            if (NumberUtil.isInteger(Math.sqrt(Math.pow(i, 2) + sizeSquared))) memoizedValue += NumberUtil
                    .countSummations(i, size);
        return memoizedValue;
    }

Popularity: 12% [?]

Project Euler : Finding Minimal Sum Path In A Matrix

The problem 81 of Project Euler gives a square matrix and requires one to find the minimal sum path. Specifically, it only required the sum of the numbers on the path. The question immediately reminded me of problem 67 and I set out solving with the same logic.

The logic has been explained in the following post of mine: Project Euler : Maximum Sum Traversing Top To Bottom In A Triangle.

The following lines of code did the work for me:

    public static int getMinimalSumPath(int[][] numbers) {
        int dimension = numbers.length - 1;
        for (int x = dimension; x >= 0; x--)
            for (int y = dimension; y >= 0; y--) {
                if (x == dimension &amp;amp;&amp;amp; y == dimension) continue;
                int val1 = x < dimension ? numbers[x + 1][y] : Integer.MAX_VALUE;
                int val2 = y < dimension ? numbers[x][y + 1] : Integer.MAX_VALUE;
                numbers[x][y] += val1 < val2 ? val1 : val2;
            }

        return numbers[0][0];
    }

Popularity: 13% [?]

Project Euler : Number Of Routes From One Corner To Another In A Grid

I have gone in a very round about way, and my explanation might not be clear. Apparently, this is a very standard combinatorics problem and can be answered at sight. Well, I did not know that, and did a few things which made me realize the combinatorial answer.

The latest problem that I solved was is Problem 15. Given a grid of 20 x 20 squares, the question asked was to find the number of routes from the top left hand corner of the grid to the bottom rightmost corner without ever backtracking.

This was an easy one too. I started out by writing at every meeting point of lines, the number of extra lines that spring out of the point. For example, at the starting point 2 lines start. Select for example the horizontal one. At the first point that it comes across, it forks into 2 lines, which is 1 extra. So I wrote 1 at this point. The same is done at all points except those on the rightmost vertical and the bottommost horizontal which contains the total number of lines passing through it.

Below is a diagram showing the same thing.

Notice the similarity with Pascal’s triangle.

1     1

1     2     1

1     3     3     1

1     4     6     4     1

1     5     10     10     5     1

1     6     15     20     15     6     1

The center element of Pascal’s triangle is given by ^{n}C_{\frac{n}{2}}. Our answer in the case of 3 x 3 squares is given by ^{6}C_{3}.

Thus our answer for 20 x 20 grid is ^{40}C_{20}.

Popularity: 6% [?]

Project Euler : Maximum Sum Traversing Top To Bottom In A Triangle

The 18th and the 67th problems in Project Euler are one and the same. The only difference is in the input test case. The problem 18 has a smaller input and 67 has a large input. For the explanation purpose, I’ll consider problem 18. The code without any modification can be extended to 67th problem.

Given a triangle of numbers, the objective is to determine the maximum sum along paths descending from the apex of the triangle to the base. Consider the example:

3

7     4

2     4     6

8     5     9     3

The maximum sum occurs along the path 3-7-4-9.

The problem required us to determine the maximum sum for any given triangle. Also an interesting thing is mentioned about the problem, in case you were considering a brute force method of checking every path:

It is not possible to try every route to solve this problem (where the base of the triangle has 100 numbers), as there are 2^(99) altogether! If you could check one trillion (10^(12)) routes every second it would take over twenty billion years to check them all. There is an efficient algorithm to solve it. ;o)

Being forewarned, I never once gave a thought to the brute force solution.

This problem was not as tricky as they tried to sound it. The solution is quite easy to see. I’ll run you through the idea as it formed in my mind. I used the top-to-bottom approach for forming the idea and coming up with the solution, and then implemented the solution in bottom-to-top sweep. I hope you have realized that a greedy solution will not work here.

Consider the triangle given above. I’ll work out the maximum path for it from top to bottom.  We start with 3. We may choose either 7 or 4. To help make this choice, consider the two triangles with apex 7 and the other with 4. So we have two smaller triangles of height 3 each. Say the maximum length for the triangle with apex 7 is x and with apex 4 is y. If x > y, we choose 7 as the next on the path, else 4.

Thus, at every step we form two triangle of height 1 smaller, and choose the apex which has the larger sum. Implemented as it is will give us the recursive solution. To get an iterative solution to this problem, one could traverse from bottom-to-top. The bottom-to-top approach is also simple. It is greedy in approach.

Consider the penultimate row, specifically the triangle with 2 as apex and 8, 5 as the base. The maximum sum in this triangle is 2+8 =  10. Replace 2 with 10. Do the same for all the triangles formed with the penultimate layer as the apex. Thus our triangle reduces to

3

7     4

10     13     15

You know what to do next. Keep applying the same till the apex of the original triangle has the maximum sum.

I have implemented the bottom-to-top method so as to avoid recursion. Here is my code:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Problem_18 {
	private static int heightOfTree = 100;
	private final String fileName = "problem_67.in";
	private int[][] tree;

	public int maxValue() throws IOException {
		readTree();

		for (int i = Problem_18.heightOfTree - 2; i >= 0; i--)
			for (int j = 0; j <= i; j++)
				tree[i][j] += tree[i + 1][j] > tree[i + 1][j + 1] ? tree[i + 1][j] : tree[i + 1][j + 1];

		return tree[0][0];
	}

	private void readTree() throws IOException {
		tree = new int[Problem_18.heightOfTree][];

		BufferedReader bufferedReader = new BufferedReader(new FileReader(fileName));
		for (int i = 0; i < Problem_18.heightOfTree; i++) {
			tree[i] = new int[i + 1];
			String[] values = bufferedReader.readLine().split(" ");
			for (int j = 0; j <= i; j++)
				tree[i][j] = Integer.parseInt(values[j]);
		}
	}

	public static void main(String[] args) throws IOException {
		System.out.println(new Problem_18().maxValue());
	}
}

Popularity: 100% [?]