Lattice paths
First read the problem description.
If we take each intersection as a node and each direction as an edge, then we can see that this is just a DAG. To count the possible paths from start to end we can observe than the number of paths of a node is the sum of the number of paths of its children. We do a topological sort of the graph and starting from the bottom right corner we go back calculating the number of paths. Since for each \(v\) the paths of its children have already been calculated, we need to just sum them.
import networkx as nx
def build_graph(n):
= nx.DiGraph()
g
def i(col, row):
return n * (row - 1) + col
for c in range(1, n + 1):
for r in range(1, n + 1):
if c != n:
+ 1, r))
g.add_edge(i(c, r), i(c if r != n:
+ 1))
g.add_edge(i(c, r), i(c, r return g
# Kahn's algorithm
def topological_sort(g):
= g.copy()
g = []
sorted_nodes = [1]
without_incoming_edges while without_incoming_edges:
= without_incoming_edges.pop()
n
sorted_nodes.append(n)= []
edges_to_remove for s in g.successors(n):
edges_to_remove.append((n, s))if g.in_degree(s) == 1: # the edge n -> s will be removed, so we check for 1 instead of 0
without_incoming_edges.append(s)for (n, s) in edges_to_remove:
g.remove_edge(n, s)return sorted_nodes
def count_paths(g, f, t):
= topological_sort(g)
sorted_nodes = {t: 1}
cache for n in reversed(sorted_nodes[:-1]):
= 0
count for s in g.successors(n):
+= cache[s]
count = count
cache[n] return cache[f]
= 20 + 1
nodes = build_graph(nodes)
g 1, nodes * nodes) count_paths(g,
137846528820
Source code of the solution(s):