Blue Bridge Cup Selected Questions Algorithm Series - Maze - DFS

This column has been included .
Today, we will comprehensively learn the relevant knowledge of DFS, including theory, templates, real questions, etc.
Depth-First Search (DFS, Depth-First Search) and Breadth-First Search (BFS, Breadth-First Search, or Breadth-First Search) are basic brute force techniques that are often used to solve graph and tree traversal problems.

Let's take the mouse walking the maze as an example to illustrate the principles of BFS and DFS. The road in the maze is intricate and complicated. After the mouse enters through the entrance, how can it find the exit? There are two options:

1. A mouse walks a maze. At each intersection, it chooses to go to the right first (of course, it is also possible to choose to go to the left first), as far as it can go; until it hits a wall and can no longer go forward, then take a step back, and this time go to the left , and then continue down. In this way, as long as you don't encounter an exit, you will go all the way, and you will not repeat it (here, it is stipulated that backtracking is not counted as repeating). This idea is DFS.

2. A group of mice walks a maze. Assuming that there are infinitely many rats, after this group of rats enters, at each intersection, some rats are sent to explore all the untraveled roads. A rat walking on a certain road, if it hits a wall and cannot move forward, stops; if the intersection it reaches has already been explored by other rats, it also stops. Obviously, all roads will be followed and not repeated until the exit is encountered. This idea is BFS.

In specific programming, the data structure of queue is generally used to implement BFS, that is, "BFS = queue"; while DFS is generally implemented by recursion, that is, "DFS = recursion".

recursion

Recursion is the "first stumbling block" when learning programming, and I think many people have difficulty understanding it. But now from a formal point of view, a recursive function is "calling itself", which is a process of "repeating".

The recursive algorithm idea is the process of gradually reducing the big problem until it becomes the smallest similar problem, and the solution of the final small problem is known, generally given the initial conditions. In the recursive process, since the solutions to the big problem and the small problem are exactly the same, the code for the big problem and the code for the small problem can be written the same.
Let's take the calculation of the Fibonacci sequence as an example, and write the code.
First we know that its recurrence relation is f(n) = f(n-1) + f(n-2). Then to print the 2020th number, the recursive code is as follows:

fib = [0 for _ in range(25)]
fib[1] = fib[2] = 1
for i in range(3,21):
    fib[i] = fib[i-1]+fib[i-2]
print(fib[20])

According to recursion, use recursive encoding instead, the code is as follows:

cnt = 0
def fib(n):
    global cnt 
    cnt += 1
    if n == 1 or n==2:
        return 1
    return fib(n-1) + fib(n-2)
print(fib(20))
print(cnt)

Let's analyze the recursive process. Taking the calculation of the 5th Fibonacci number as an example, the recursive process is as follows:
insert image description here
this recursive process does a lot of repetitive work, for example, fib(3) is calculated twice, but in fact, only one calculation is enough.
In the fib(3) function, it calls itself 2 times. When computing fib(n), the amount of computation is staggering. I used cnt to count the number of recursion in the function. When calculating the 20th Fibonacci number, cnt=13529.
In order to avoid repeated calculation of sub-problems during recursion, you can save the result when the sub-problem is solved, and return the saved result directly when the result is needed again. This technique of storing the results of solved subproblems is called "Memoization". Memoization is a common optimization technique for recursion, here is the Fibonacci rewritten with "memoization + recursion":

cnt = 0
data = [0 for _ in range(25)]
def fib(n):
    global cnt 
    cnt += 1
    if n == 1 or n==2:
        data[n] = 1
        return data[n]
    if data[n] != 0:
        return data[n]
    data[n] = fib(n-1)+ fib(n-2)
    return data[n]
print(fib(20))
print(cnt)

Let's see how recursion solves permutation related problems.
First of all, we need to clearly rank what is the problem?
Given some numbers, generate their permutations, this is a common requirement and often appears in the blue bridge cup problem. We gave the permutations() system function for permutation in the "Blue Bridge Cup Selected Questions Series - Violent Spelling" , do you still have an impression?
The system function permutations(), although useful, cannot be completely relied upon. Because not all the scenes that need to be arranged can directly use next_permutation(), sometimes you still have to write the arrangement yourself. The example question "Winter Vacation Homework" for a while will time out if you use the next_permutation() function, so you have to write the permutation algorithm yourself. Let's analyze the two ideas of self-written code!

Self-written full permutation algorithm 1

1. We set the number to be {1 2 3 4 5...n}, then the idea of ​​recursive total permutation is:
make the first number different and get n number sequences. The method is: exchange the first number with each subsequent number.

1 2 3 4 5…n
2 1 3 4 5…n

n 2 3 4 5…1

For the above n sequences, as long as the first number is different, no matter how the following n−1 numbers are arranged, these n​ sequences are different. This is the first level of recursion.
2. Continue: In each sequence above, remove the first number and perform a similar arrangement for the following n-1​ numbers. For example, enter the second layer from {2 1 3 4 5...n} in line 2 above (remove the first 2):

1 3 4 5…n
3 1 4 5…n

n 3 4 5…1

For the above n-1 numbers, as long as the first number is different, no matter how the next n-2 numbers are arranged, the n-1 numbers are different.

This is the second level of recursion.
3. Repeat the above steps until all numbers are used up.
code show as below:

a = [1,2,3,4,5,6,7,8,9,10,11,12,13]
def dfs(s,t):
    if s == t:
        for i in range(t+1):
            print(a[i],end = '')
        print('\n')
        return
    for  i  in range(s,t+1):
        a[s],a[i] = a[i],a[s]
        dfs(s+1,t)
        a[s],a[i] = a[i],a[s]

n = 3
dfs(0,n-1)

The output of the above code is:

1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
3 1 2

but! This code has a fatal flaw: it cannot print the arrangement in ascending order. And the problems we encounter often need to be output in order.
All there is another self-written full permutation algorithm

Self-written full permutation algorithm 2

Without further ado, let's go directly to the code.

a = [1,2,3,4,5,6,7,8,9,10,11,12,13]
vis = [0 for _ in range(20)]
b = [0 for _ in range(20)]
def dfs(s,t):
    if s == t:
        for i in range(t):
            print(b[i],end = '')
        print('\n')
        return
    for  i  in range(t):
        if  not  vis[i]:
             vis[i]=True 
             b[s]=a[i]
             dfs(s+1,t)
             vis[i]=False


n = 3
dfs(0,n)

Let's take a question to practical combat:

Topic description

A labyrinth playground on Planet X is built on a hillside. It consists of 10×10 interconnected small rooms.

A large letter was written on the floor of the room. We assume that the player is standing facing uphill, then:

L means go to the left room
R means go to the right room
U means go to the uphill room
D means go to the downhill room.

The inhabitants of Planet X are a bit lazy and don't want to think hard. They prefer to play games of luck. So is this game!

At the beginning, the helicopter put 100 players into small rooms. Players must move according to the letters on the ground.

The maze map is as follows:

UDDLUULRUL
UURLLLRRRU
RRUURLDLRD
RUDDDDUUUU
URUDLLRRUU
DURLRLDLRL
ULLURLLRDU
RDLULLRDDD
UUDDUDUDLL
ULRDLUURRR

Please calculate, in the end, how many players will get out of the maze instead of going around in circles?

If you don't understand the rules of the game, here is a simplified illustration of a 4x4 maze:Please add image description

enter description

none.

output description

none.

Detailed code

move=[['U', 'D', 'D', 'L', 'U', 'U', 'L', 'R', 'U', 'L'], ['U', 'U', 'R', 'L', 'L', 'L', 'R', 'R', 'R', 'U'], ['R', 'R', 'U', 'U', 'R', 'L', 'D', 'L', 'R', 'D'], ['R', 'U', 'D', 'D', 'D', 'D', 'U', 'U', 'U', 'U'], ['U', 'R', 'U', 'D', 'L', 'L', 'R', 'R', 'U', 'U'], ['D', 'U', 'R', 'L', 'R', 'L', 'D', 'L', 'R', 'L'], ['U', 'L', 'L', 'U', 'R', 'L', 'L', 'R', 'D', 'U'], ['R', 'D', 'L', 'U', 'L', 'L', 'R', 'D', 'D', 'D'], ['U', 'U', 'D', 'D', 'U', 'D', 'U', 'D', 'L', 'L'], ['U', 'L', 'R', 'D', 'L', 'U', 'U', 'R', 'R', 'R']]
def tes (y,x,a):
    if y<0 or y>9 or x<0 or x>9:
        return 1
    elif a>100:
        return 0
    if move[y][x]=='U':
        return tes(y-1,x,a+1)
    elif move[y][x]=='D':
        return tes(y+1,x,a+1)
    elif move[y][x]=='R':
        return tes(y,x+1,a+1)
    else:
        return tes(y,x-1,a+1)
res=0
for y in range(10):
    for x in range(10):        
        res+=tes(y,x,0)
print(res)



That's all for this time, see you next time.

Guess you like

Origin blog.csdn.net/m0_51951121/article/details/122990741