Non-Linear Recursive Backtracking: Li Yin April 5, 2019
Non-Linear Recursive Backtracking: Li Yin April 5, 2019
Backtracking
Li Yin1
April 5, 2019
1
www.liyinscience.com
ii
Non-linear Recursive Backtracking
iii
iv NON-LINEAR RECURSIVE BACKTRACKING
0.1 Enumeration
0.1.1 Permutation
Before I throw you more theoretical talking, let us look at an example: Given
a set of integers 1, 2, 3, enumerate all possible permutations using all items
from the set without repetition. A permutation describes an arrangement
or ordering of items. It is trivial to figure out that we can have the following
six permutations: [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], and [3, 2, 1].
Implicit Graph In the graph, each node is either a partial or final solu-
tion. If we look it as a tree, the internal node is a partial solution and all
leaves are final solutions. One edge represents generating the next solution
based on the current solution. The vertices and edges are not given by an
0.1. ENUMERATION v
explicitly defined graph or trees, the vertices are generated on the fly and
the edges are implicit relation between these nodes.
Give the input of a=[1, 2, 3], we call the above function with the following
code:
1 a = [1 , 2 , 3]
2 n = len (a)
3 ans = [ [ None ] ]
4 used = [ F a l s e ] ∗ l e n ( a )
5 ans = [ ]
vi NON-LINEAR RECURSIVE BACKTRACKING
1 [1]
2 [1 , 2]
3 [1 , 2 , 3]
4 backtrack : [1 , 2]
5 backtrack : [1]
6 [1 , 3]
7 [1 , 3 , 2]
8 backtrack : [1 , 3]
9 backtrack : [1]
10 backtrack : []
11 [2]
12 [2 , 1]
13 [2 , 1 , 3]
14 backtrack : [2 , 1]
15 backtrack : [2]
16 [2 , 3]
17 [2 , 3 , 1]
18 backtrack : [2 , 3]
19 backtrack : [2]
20 backtrack : []
21 [3]
22 [3 , 1]
23 [3 , 1 , 2]
24 backtrack : [3 , 1]
25 backtrack : [3]
26 [3 , 2]
27 [3 , 2 , 1]
28 backtrack : [3 , 2]
29 backtrack : [3]
30 backtrack : []
Two Passes Therefore, we can say backtrack visit these implicit vertices
in two passes: First forward pass to build the solution incrementally, second
backward pass to backtrack to previous state. We can see within these two
passes, the curr list is used as all vertices, and it start with [] and end with
[]. This is the character of backtracking.
0.1.2 Combination
Try to modify the above code so that you can collect the
power set.
Note: To generate the power set, backtracking is NOT the only solution,
if you are interested right now, check out Section ??.
We can look it as another way, there are in total n objects, and each object
we can make two decisions: inside of the subset or not, therefore, this makes
2n .
0.1. ENUMERATION ix
With the printing, we can see the whole process, path changes as the de-
scription of backtrack.
[0 , 1]
[0 , 1 , 2]
x NON-LINEAR RECURSIVE BACKTRACKING
[0 , 1 , 2 , 4]
[0 , 1 , 2 , 4 , 3]
[0 , 1 , 2 , 4] backtrack
[0 , 1 , 2 , 4 , 5]
[0 , 1 , 2 , 4 , 5 , 6]
[0 , 1 , 2 , 4 , 5] backtrack
[0 , 1 , 2 , 4] backtrack
[0 , 1 , 2] backtrack
[0 , 1] backtrack
[0] backtrack
We can see each state, we can always have a matching backtrack state.
0.1.4 Analysis
Backtracking VS DFS The implementation of Backtracking is equiva-
lent to a DFS on the implicit or explicit search space and visiting each vertex
no more than once. Backtracking is a technique to build up solution spaces
incrementally and each exactly only once. And once one path reaches to the
end, it backtrack to its previous state and try another candidate. DFS is a
natural way to implement backtarck technique.
0.2.1 Sudoku
We will start with a sudoku problem due to its popularity in magazines, and
we will discuss classical eight queen problem, traveling salesman probelm
(TSP), and we leave exercises to such problems such as puzzles, sudoku and
so on.
Solving Sudoku with Backtracking Now, let us see how we can use
backtrack and search prunning to implement a sudoku solver.
The following function is implement to find empty spots and state record.
1 d e f getEmptySpots ( board , rows , c o l s , row_state , c o l _ s t a t e ,
grid_state ) :
2 ’ ’ ’ g e t empty s p o t s and f i n d i t s c o r r e s p o n d i n g v a l u e s i n O( n
∗n ) ’ ’ ’
3 empty_spots = {}
4 # i n i t i a l i z e t h e s t a t e , and g e t empty s p o t s
5 f o r i i n r a n g e ( rows ) :
6 f o r j in range ( c o l s ) :
7 i f board [ i ] [ j ] :
8 # s e t that b i t to 1
9 s e t S t a t e ( i , j , board [ i ] [ j ] −1 , row_state , c o l _ s t a t e ,
grid_state )
10 else :
11 empty_spots [ ( i , j ) ] = [ ]
12
13 # g e t p o s s i b l e v a l u e s f o r each s p o t
14 f o r i , j i n empty_spots . k e y s ( ) :
15 f o r v in range (9) :
16 i f c h e c k S t a t e ( i , j , v , row_state , c o l _ s t a t e , g r i d _ s t a t e )
:
17 empty_spots [ ( i , j ) ] . append ( v+1)
18
19 r e t u r n empty_spots
xiv NON-LINEAR RECURSIVE BACKTRACKING
Now, with our existing grid, we get the empty spots and sort them by the
length of possible values.
The prunning appears when the checkState returns False. We prun braches
that appears invalid already and only handle brachs that up till now are
valid.
0.3 Summary
BFS and DFS are two of the most universal algorithms for solving practical
problems. Each suits better than the other to specific type of problems.
• For BFS, it suits problems that ask the shortest paths( unweighted )
from a certain source node to a certain destination, whether it is single
sourced or all-pairs. Or in some cases, the questions requires us only
traverse the graph for a certain steps (levels). Because BFS is iterative
and can traverse the nodes level by level.
• Use either BFS or DFS when we just need to check correctness (whether
we can reach a given state to another.
When and How When Bidirectional search can find the shortest path
successfully if all the paths are assigned uniform costs.
How When the graph from each side is not balanced: each node has
various branch factors. We take two queues: sourceQueue for BFS in forward
direction from source to target and targetQueue which is used to do the
BFS from the target towards the source in backward direction. We try to
alternate between the two queues: sourceQueue and targetQueue; basically
in every iteration we choose the smaller queue for the next iteration for
the processing which effectively helps in alternating between the two queues
only when the swapping between the two queues is profitable.
This helps in the following way: As we go deeper into a graph the number
of edges can grow exponentially. Since we are approaching in a balanced way,
selecting the queue which has smaller number of nodes for the next iteration,
we are avoiding processing a large number of edges and nodes by trying to
having the intersection point somewhere in the middle.
Since we are processing both the target and source queue we are not
going to much depth from any direction, either in forward direction (i.e,
while processing source queue) or in backward direction (i.e, target queue
which searches from target to source in backward manner).
Implementation
0.5 Bonus
Generating combinations, permutation uniformly at random.
0.6 Exercises
0.6.1 Knowledge Check
0.6.2 Coding Practice
Cycle Detection
1. 207. Course Schedule (medium)
Topological Sort
Connected Component
1. 323. Number of Connected Components in an Undirected Graph
(medium).
2. 130. Surrounded Regions(medium)
3.
0.6. EXERCISES xvii
Mix
1. 210. Course Schedule II (medium, cycle detection and topological
sort).
Backtracking
1. 77. Combinations
1 Given two i n t e g e r s n and k , r e t u r n a l l p o s s i b l e
c o m b i n a t i o n s o f k numbers out o f 1 . . . n .
2
3 Example :
4
5 I nput : n = 4 , k = 2
6 Output :
7 [
8 [2 ,4] ,
9 [3 ,4] ,
10 [2 ,3] ,
11 [1 ,2] ,
12 [1 ,3] ,
13 [1 ,4] ,
14 ]
(a) Each of the digits 1-9 must occur exactly once in each row.
(b) Each of the digits 1-9 must occur exactly once in each column.
(c) Each of the the digits 1-9 must occur exactly once in each of the
9 3x3 sub-boxes of the grid.
xviii NON-LINEAR RECURSIVE BACKTRACKING