This looks like a standard pathfinding problem: find a path from the start cell (value 1) to the end cell (value 2). The added constraint is what makes it different. The path must visit every walkable cell exactly once. It cannot skip any empty square, and it cannot revisit one.
That constraint turns this into a problem of counting Hamiltonian paths on a grid graph, restricted to a specific start and end. Counting Hamiltonian paths is NP-hard in general, but the constraint m * n <= 20 tells us an exponential solution is acceptable here.
The plan is to explore all possible paths from start to end and count only the ones that visit every non-obstacle cell. With at most 20 non-obstacle cells, enumerating all possibilities with backtracking finishes quickly.
1 <= m * n <= 20 → The grid holds at most 20 cells. An exponential search over paths is feasible at this size, and there is no polynomial algorithm for the general problem.-1 <= grid[i][j] <= 2 → Four cell types. We preprocess the grid once to locate the start, the end, and the count of walkable cells.Explore every possible path from start to end with depth-first search. At each cell, try moving in all four directions. Mark a cell as visited when stepping onto it and unmark it when backtracking, which enumerates all paths without revisiting cells.
To decide when a path counts, precompute the total number of non-obstacle cells (the start and end cells included). As the search walks, track how many cells it has visited. When it reaches the end cell, compare that count to the total. If they match, the path visited every walkable cell exactly once, so it is a valid Hamiltonian path.
The grid holds at most 20 cells. The branching factor is at most 4, the depth is at most 20, and the no-revisit rule prunes the search tree heavily, so this runs quickly at this input size.
The backtracking approach explores the same subproblems more than once. When two different paths reach the same cell having visited the same set of cells, the remaining work is identical, yet backtracking redoes the entire subtree. The next approach caches the result for each (current cell, visited set) pair.
Different paths that arrive at the same cell with the same set of visited cells produce the same number of valid completions. Caching that result avoids re-exploring identical subtrees.
To cache it, the visited set has to become a compact, hashable key. Assign each non-obstacle cell an index from 0 to k-1 (where k is the total number of walkable cells), and represent the set of visited cells as a bitmask: an integer where bit i is set if cell i has been visited. The state becomes (current cell index, bitmask of visited cells), and its value is the number of ways to reach the end cell while visiting every remaining unvisited cell.
With at most 20 cells, the bitmask has at most 2^20 = 1,048,576 values, and there are at most 20 cells, so the state space is bounded by 20 * 2^20, around 20 million. That is feasible, and most of those states are never reached because a cell can only hold valid masks that include its own bit.
Memoizing on (cell, mask) is sound because the number of valid completions from a state depends only on the current cell and the set of already-visited cells, not on the order in which they were visited. The remaining choices, which cells are still reachable and unvisited, are fully determined by the mask. Two paths that arrive at cell X having visited the set {A, B, C} therefore have an identical count of ways to finish, so caching one and reusing it for the other is exact.
fullMask = (1 << k) - 1.(cellIndex, visitedMask).cellIndex is the end cell and visitedMask == fullMask, return 1. If cellIndex is the end cell but not all cells are visited, return 0.visitedMask, add the bit for the neighbor to the mask and recurse.dp(startIndex, 1 << startIndex).