Given is a N*N grid.Now we need to find a good path of maximum length , where good path is defined as follow :
- Good path always start from a cell marked as 0
- We are only allowed to move Left,Right,Up Or Down
- If the value of ith cell is say A, then value of next cell in the path must be A+1.
Now given these few conditions, I need to find out the length of maximum path that can be made. Also I need to count such paths that are of maximum length.
Example : Let N=3 and we have 3*3 matrix as follow :
0 3 2
3 0 1
2 1 0
Then maximum good path length here is 3 and the count of such good paths is 4.
0 3 2
3 0 1
2 1 0
0 3 2
3 0 1
2 1 0
0 3 2
3 0 1
2 1 0
0 3 2
3 0 1
2 1 0
This problem is a variation of Longest Path Problem, however your restrictions make this problem much easier, since the graph is actually a Directed Acyclic Graph (DAG), and thus the problem is solveable efficiently.
Define the directed graph
G=(V,E)
as following:V = { all cells in the matrix}
(sanity check: |V| = N^2)E = { (u,v) | u is adjacent to v AND value(u) + 1 = value(v) }
Note that the resulting graph from the above definition is a DAG, because you cannot have any cycles, since it will result in having some edge
e= (u,v)
such thatvalue(u) > value(v)
.Now, you only need to find longest path in a DAG from any starting point. This is done by topological sort on the graph, and then using Dynamic Programming:
When you are done, find the node
v
with maximal valueD(v)
, this is the length of the longest "good path".Finding the path itself is done by rerolling the above, retracing your steps back from the maximal D(v) until you reach back the initial node with value 0.
Complexity of this approach is
O(V+E) = O(n^2)
Since you are looking for the number of longest paths, you can modify this solution a bit to count the number of paths reached to each node, as follows:
The above will find you for each node
v
the number of "good paths"D(v)
that reaches it. All you have to do now, is find the maximal valuex
that has sum nodev
such thatvalue(v) = x
andD(v) > 0
, and sum the number of paths reaching any node withvalue(v)
:Notes: (1) - a "regular" sort works here to, but it will take O(n^2logn) time, and topological sort takes O(n^2) time
(2) Reminder, (u,v) is an edge if: (1)
u
andv
are adjacent (2) value(u) + 1 = value(v)I did it using ActionScript, hope it's readable. I think it is working correctly but I may have missed something.
Sample output:
You can do this with a simple Breadth-First Search.
First find all cells marked 0. (This is O(N2).) On each such cell put a walker. Each walker carries a number 'p' initialized to 1.
Now iterate:
All walkers stand on cells with the same number k. Each walker looks for neighboring cells (left, right, up or down) marked with k+1.
If no walker sees such a cell, the search is over. The length of the longest path is k, and the number of such paths is the sum of the p's of all the walkers.
If some walkers see such numbers, kill any walkers that don't.
Each walker moves into a good neighboring cell. If a walker sees more than one good cell, it divides into as many walkers as there are good cells, and one goes into each. (Each "child" has the same
p
value its "parent" had.) If two or more walkers meet in the same cell (i.e. if more than one path led to that cell) then they combine into a single walker, whose 'p' value is the sum of their 'p' values.This algorithm is O(N2), since no cell can be visited more than once, and the number of walkers cannot exceed the number of cells.
I implemented it in my own Lisp dialect, so the source code is not going to help you that much :-) ...EDIT: Added a Python version too.
anyway the idea is:
paths(i, j) --> (maxlen, number)
that returns maximal length of paths starting from(i, j)
and how many of them are present..(i, j)
with valueM[i][j]+1
will callpaths(ni, nj)
to get the result for valid neighborspaths
that checks the cache first and callscompute-paths
otherwise;compute-paths
callspaths
when processing neighbors. The caching of a recursive call is roughly equivalent to an explicit Dynamic Programming approach, but sometimes easier to implement.To compute the final result you basically do the same computation but adding up the result for all
0
cells instead of considering neighbors.Note that the number of different paths can become huge, and that's why enumerating all of them is not a viable option and caching/DP is a must: for example for a
N=20
matrix with valuesM[i][j] = i+j
there are 35,345,263,800 maximal paths of length 38.This algorithm is O(N^2) in time (each cell is visited at most once) and requires O(N^2) space for the cache and for the recursion. Of course you cannot expect to get anything better than this given that the input is composed of N^2 numbers itself and you need at least to read them to compute an answer.
Edit
The following is a transliteration of the above in Python, that should be much easier to understand if you never saw Lisp before...