The problem is a diagonal-counting one, as can be seen here:
https://wwwcgi.cdf.toronto.edu/~heap/cgi-bin/Solvent/wiki.pl?Problem_Solving_Home_Page/DiagonalCount
(username sleuth, password eureka)
So here goes:
Step 1: Understand the problem
Our problem here involves a rectangular grid made up of squares. There are m rows and n columns of squares (m and n are integers).
We are looking for an integer d which represents the number of squares crossed by a diagonal cutting through our grid from square (0,0) to square (m,n) (where the coordinates represent the square's position along the grid). We want to devise a formula to know how many squares are crossed by the diagonal, not counting squares where the diagonal passes between them (i.e. the diagonal cuts through the meeting-corner of 4 squares, and the squares counted are the origin square and the destination square).
Step 2: Devise a plan
We can test small grids and look for patterns, and then suggest a formula based on our findings. There will be certain special cases: when m=n, when n can be divided by m (and vice-versa), and when n=m+1 (and vice-versa). We'll simplify and set that n>=m so that we don't test grids that are reflections of each other (for instance, m=3 and n=4 would have the same diagonal crossings as m=4 and n=3).
We'll want to pay attention to when the diagonal crosses another line, as this signifies that it has entered a new square.
Step 3: Carry out the plan
Testing a number of different values of m and n, we can find that:
When m=1, the diagonals d=n.
When m=2, the diagonals d=((ceiling of n/2)*2)
At first I considered the possibility that the diagonals would be (ceiling of n/m)*m, but this does not continue into m=3.
After some investigation, I came across the hint on another blog to examine boundaries (added to the plan above). Let's examine those with a table:
As we can see, the number of boundaries crossed is equal to (m-1)+(n-1), which makes sense given that the grid has m-1 horizontal lines and n-1 vertical lines.
Given this information, we can further say that each boundary crossing means another square is added... right? Well, not all crossings are equal. For instance, what if a diagonal crosses horizontally and vertically at the same time? Then, on a 2x2 grid, only 2 squares would be entered.
As the image shows (yeah, yeah, there's a small offset), we only enter 2 squares!
This occurs whenever m=n, as in every case of m=n the grid can be reduced to 2x2 grids (a 3x3 grid would simply have 3 squares entered and 4 boundary crossings, even though it may be 2 overlapping 2x2 grids).
These sorts of reductions work for different m & n pairs too, when there is a common factor between m & n. In such situations, we can divide and simplify:
In these moments, the formula for the number of squares appears to be closer to the length of n, or m*n/GCD.
As well, when these larger grids can be reduced to smaller grids, they produce more intersections (rather than traditional boundary crossings). For instance, 3x6 produces 3 intersections, which means it only covers 6 squares, rather than the 7 of 3x5 or the 9 of 3x7.
Primes then seem to be the mysterious grids. A grid of 2x5 produces 6 squares; 3x11 produces 13 squares. What might the pattern be? (cue some time spent trying to come up with something complicated... before resorting to the simple)
Well, let's make a big graph with squares, GCD and boundaries.As we can see, when the GCD is 1, the number of squares crossed is m+n-1, which is also the number of boundaries crossed +1. This makes sense as there will be the starting square which is counted though the line does not cross 'into' it.
When the GCD is not 1, we can reduce the problem, but m*n/GCD is not quite correct, as otherwise 4x6 would be 12, not 8. What gives? Well, actually, the problem is reduced to a smaller problem times the GCD, in such that it becomes GCD*((m/GCD)+(n/GCD)-1).
Thus, we end up with a formula:
squares(m,n):
factor=1;
if m>n, factor=m//n; else, factor=m%n;
if factor==1, return m+n-1; else, return factor*squares(m/factor,n/factor);
Hurray!
Here's the Python code:
Let us never speak of this again ;)