My first attempt to solve this (see code for approach A below) used a straight-forward recursive brute-force approach based on the observation the the number routes R to get from corner to corner in a rectange of size (X,Y) obeys the following relation: R(X,Y) = R(X-1,Y) + R(X,Y-1) with the boundary conditions R(X,0) = 1 and R(0,Y) = 1.
The program for approach A produces the correct answers. However, the run-time increased so rapidly with the problem size that it was hopeless to compute the answer for a 20 x 20 grid within a minute. The following shows the graph of the run-time versus the grid size.

P.S.: After reading the notes for the problem, I realized there is a much more elegant way to solve this problem. I won't spoil it by giving that answer away.
Code for approach A:
%% Project Euler, problem 15
%%
%% Find number of corner-to-corner routes (without backtracking) in a 20x20 grid
-module(euler15a).
-author('Cayle Spandon').
-export([solve/0, solve/1, routes_in_grid/2]).
routes_in_grid(X, Y) ->
if
(X == 0) or (Y == 0) ->
1;
true ->
routes_in_grid(X - 1, Y) + routes_in_grid(X, Y - 1)
end.
solve() ->
solve(20).
solve(N) ->
routes_in_grid(N, N).
Code for approach B:
%% Project Euler, problem 15
%%
%% Find number of corner-to-corner routes (without backtracking) in a 20x20 grid
-module(euler15b).
-author('Cayle Spandon').
-export([solve/0, solve/1, routes_in_grid/2]).
routes_in_grid(X, Y) ->
Solutions = dict:new(),
{Routes, _} = routes_in_grid(X, Y, Solutions),
Routes.
routes_in_grid(0, _Y, Solutions) ->
{1, Solutions};
routes_in_grid(_X, 0, Solutions) ->
{1, Solutions};
routes_in_grid(X, Y, Solutions) ->
case dict:find({X, Y}, Solutions) of
{ok, Routes} ->
{Routes, Solutions};
error ->
{Routes1, Solutions1} = routes_in_grid(X - 1, Y, Solutions),
{Routes2, Solutions2} = routes_in_grid(X, Y - 1, Solutions1),
NewRoutes = Routes1 + Routes2,
NewSolutions = dict:store({X, Y}, NewRoutes, Solutions2),
{NewRoutes, NewSolutions}
end.
solve() ->
solve(20).
solve(N) ->
routes_in_grid(N, N).
No comments:
Post a Comment