Fried chicken's detailed depth-first search, dfs is actually very simple!

dfs wanted to write an article a long time ago, and finally found an excuse to write a depth-first search for my brother!

basic concepts

Deepth first search is also called dfs. The basic idea is to start from a given point, choose a path and go on without hitting the south wall and not looking back. Whether you like it or not, it's so specific.

Head hit a brick wall until you come to find that when the current path is not feasible, only this time back to back through the stack + backtracking to achieve, then the specific how do ↓

example

There are many applications of dfs, the most basic is the problem of finding the number of paths in a maze. For example, we choose the following simple maze ↓ to start walking from a, and each time we can only walk one square in four directions up, down, left, and right, until the end of b. Seek all the ways to go.
Simple maze

Algorithmic thinking

First confirm that there is no problem with the current position and you can go . Then start from the current position, choose a direction to start the test, if you can go in this direction, continue to choose a direction from this new position to test...until you hit the south wall and turn back , or until you reach the exit of the maze

Is it familiar? Correct! The steps we need to do at every position are one! kind! of! So we can do it through recursion .

Recursion must consider the recursive exit (also called baseline conditions, boundary conditions, whatever you like) What is our recursive exit? Where can I end this function? (Actually, as mentioned above) Go to the exit!

Three questions

Before looking at the code, stop and think about three questions:

  1. What does it mean to go ?
  2. How to choose the direction of temptation ?
  3. How to turn around ?

Reply

  1. A point that can be walked is satisfied: (1) This point is in this picture (2) This point is a pathway (in a simple maze, it is not a wall). ifJust use one to judge.
  2. Choose the direction of the trial , which is where you should go next. There are several possible choices. It is necessary to traverse these choices (a single choice is directly added to later recursion, and multiple choices use a forloop to traverse all)
  3. Going back is going back , because if you want to go back and show that your point is no longer feasible, then undo all the things you have done to this position . If you need to mark this position as x in order to go to this position, then restore the original state of this position.

For example, in our maze problem, the point reachable from a point is its four positions, up, down, left, and right, so we traverse these four positions. How to implement it in a graph represented by a two-dimensional array? Point a (x, y) above is (x-1, y), below is (x+1, y), left: (x, y-1) right: (x, y+1)
Insert picture description here
Of course you can also Use four recursive call statements to achieve ↓ where g represents the graph

 g[x][y] = ' '; //标记通路
 dfs(x + 1, y); //往下试探
 dfs(x - 1, y); //往上试探
 dfs(x, y + 1); //往右试探
 dfs(x, y - 1); //往左试探
 g[x][y] = 'o';  //回溯,撤销操作

A little tricky method (if you don't want to see it, use the above method to test, you can skip to the code description):

Suppose a 4x2two-dimensional array (if you don’t understand a two-dimensional array, using two one-dimensional is the same, the specific method will be described later), the first dimension has four quantities, indicating the four directions of up, down, left, and right, and the second dimension has two Each quantity represents xa representation y, that is, xif yyou try in this direction, or how to change it↓

int go[4][2] = {
    
    {
    
    1, 0},{
    
    -1, 0},{
    
    0, 1},{
    
    0, -1}};//上下左右试探四个方向

The heuristic method of a two-dimensional array is as above, and the curly braces inside each represent a direction. For example, (x, y)if I want to go up in this position , I (x + go[1][0], y + go[1][1])can get it smoothly (x - 1, y).

Is it too much trouble to use such an array? No, if you use an array of temptations this thing up and down, you can use a j = 0~3for loop to achieve traversal. Inside the loop(x + go[j][0], y + go[j][1])

 g[x][y] = ' ';                  //标记通路
 for(int j = 0; j < 4; j++)     //试探四个方向
     dfs(x + go[j][0], y + go[j][1]);
 g[x][y] = 'o';                  //回溯,,撤销操作

Using two one-bit arrays to test is the same, except that the position changes describing x and y are divided into two arrays instead of being placed in the second dimension. It will be mentioned at the end of the article.

Code description

Before writing the code, let's go through the idea again:

  1. Determine if the current position can go
  2. Mark if you can walk, and then start from this position to explore the four directions up, down, left, and right
  3. The recursive exit is to the end (current position == end position)

ps: Here, the path of the maze is orepresented by, the wall is xrepresented by and the two-dimensional matrix g of the graph and some variables are all global. If you don’t want to write like this, you can put it in the parameter

#include<bits/stdc++.h>
using namespace std;
const int N = 505;              //假设地图大小不超过这个范围
char g[N][N];
int n, tx, ty;                  //图的实际大小,终点坐标
int go[4][2] = {
    
    {
    
    1, 0},{
    
    -1, 0},{
    
    0, 1},{
    
    0, -1}};//上下左右试探四个方向
void printGraph(){
    
    
    //输出图
    for(int i = 0; i < n; i++){
    
    
        for(int j = 0; j < n; j++){
    
    
            cout<<g[i][j];
        }
        cout<<endl;
    }
}//printGraph()
void dfs(int x, int y){
    
    
    //从图g的当前位置(x,y)走到终点(tx,ty)的深搜
    if(x == tx && y == ty){
    
     //走到终点
        g[x][y] = ' ';      //终点也标记一次通路,或者你也可以用其它特殊字符标记终点
        printGraph();
        return;
    }
    if(g[x][y] == 'o' && x >= 0 && y >= 0 && x < n && y < n){
    
    //这个点可以走吗?
        g[x][y] = ' ';                  //标记通路
        for(int j = 0; j < 4; j++){
    
         //试探四个方向
            dfs(x + go[j][0], y + go[j][1]);
        }
        g[x][y] = 'o';                  //回溯,能执行到这里说明这个点已经不可行或者可行解已经输出。还原这个位置的状态
    }

}//dfs()
int main(){
    
    
    int x, y;
    cin>>n;         //图的边长
    cin>>x>>y;      //起点
    cin>>tx>>ty;    //终点
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            cin>>g[i][j];
    cout<<endl;
    dfs(x, y);
    return 0;
}

Test case

8
0 0
7 7
oxxxxxxx
oooooxxx
xoxxooox
xoxxoxxo
xoxxxxxx
xoxxooox
xooooxoo
xxxxxxxo

That's it, isn't it pretty simple? In fact, the idea is three sentences:

  1. Judging whether the current point is feasible
  2. Modify the state of this point if feasible , and then recursively test all the points reachable by this point
  3. Go back after the trial is complete and restore the original state at this point

If you need to request the number of paths, just change the recursive exit operation. Deep search is suitable for finding the number of paths (the number of feasible solutions), while wide search is suitable for finding the shortest path (the best feasible solution). Next time write a wide search. .

Two one-bit arrays for testing

Ah, I almost forgot to experiment with two one-digit arrays. It is to use two one-bit arrays to represent the trial direction of x and y respectively.

int dy[4] = {
    
    0,1,0,-1}; //控制左右移动
int dx[4] = {
    
    -1,0,1,0}; //控制上下移动

Note that when using two one-digit arrays, the corresponding subscripts must match. That is, when going up, (x + dx[j], y + dy[j])the jcorresponding position must match in the two arrays.

Guess you like

Origin blog.csdn.net/weixin_44559752/article/details/106752330