No depth-first search? Read this article on the depth-first search of the algorithm detailed explanation

foreword

Hello everyone, I am Bubble, an algorithm enthusiast. There are many ups and downs and 'big mountains' on the road of learning algorithms. I think everyone has a deep understanding. I think that there are several very difficult points in learning algorithms, and they bear the brunt It is depth-first search and breadth-first search. Although I understand what it means, I can't type out the code at all, and I can't write basic questions, which makes me very confused. This is not the case with the sorting I learned before. why? In fact, it is because you did not remember the template while understanding the algorithm. There is always a saying in y that is very good. You are not constructing the algorithm, you are learning to use the template. Yes, this is dozens of times in human history. The crystallization of the wisdom of various scientists for years or even hundreds of years is definitely difficult for beginners, so today's article is here.

Today's article is just to help students who are still stuck in depth-first search and really can't write code. Reading this article may give you a different experience. Here I imitate the Yan-style dp analysis method and make my own. The simple dfs four-step method, keep in mind the four steps, the maze problem, the arrangement problem is not afraid of not doing it at all!

content

Algorithm Brief

Exercise 1: Naval Battles

Topic description

input format

output format

Exercise 2: Arrangement

Topic description

input format

output format

Summarize


Algorithm Brief

Depth-first search:

It is a kind of graph traversal method, which is implemented by stack. Depth-first search is similar to pre-order traversal of trees.

In human terms, its idea is not to hit the south wall and not to look back, keep walking to a point until you can't go and then consider other directions until all points have been traversed. Obviously, depth-first search is a recursive process.

Maybe you can't feel his charm just by saying, let's take a look at the picture above.

Because the blogger's drawing is too ugly, so I borrowed the data structure of Zhejiang University. Here is a picture, all the points have not been visited.

 

Then we start from the first point, the light bulb is on, if in the code we need an array to keep track of the paths traveled.

 

 Then we went to the right and found that we didn't pass, and then we went here

 After you get here, you find that you can only go left, then continue to go left

 At this time, we found that there are two paths to take. Is there any hesitation? No, we all traversed in the end, so we're done, choose the above, and go!

 

After walking, we found that there was no way to go, so we went back the same way, back to the location where we just made the choice.

 

Then choose the place where you haven't been before and continue to walk

 

Finish

I believe that everyone can clearly see how the depth-first search works by looking at the picture, but how should the code be written in the actual application? We introduce a few examples to give you a deeper understanding of depth-first search.

Follow our four-step method, the first step, save the map, direction, mark the array

Everyone has to read the question to decide what to store the image array, the direction array, and the mark array. Here we write it as a normal two-dimensional array and up, down, left and right.

const int N = 10001;
int dx[] = {0,1,-1,0};
int dy[] = {1,0,0,-1};
int s[N][N];
bool vis[N][N];

The first layer is the data range, the second layer and the third layer are the direction. If you are at 1 1 at this time, then +0 +1 becomes 1 2, then it is the right one, +1 +0 is 2 1 and goes down one . All four directions are like this, if it is eight directions, you need more

int dx[] = {1,0,0,-1,1,-1,1,-1}
int dy[] = {0,1,-1,0,1,-1,-1,1}

The first step is solved, let's start the second step

Step 2: Find the starting point, the title requirements, and start dfs

For example, if we are asked to find a connected block, we can loop the entire graph, enter two fors, and then enter the search if the position of the graph is equal to the character or number of which connected block, the code is as follows

for(int i=1;i<=n;i++)
{
    for(int j=1;j<=m;j++)
    {
        if(s[i][j]=='*')
        {
            dfs(i,j);
        }
    }
}

Then comes our third step, the writing of the dfs function

How to write the dfs function, first mark the current position has been passed, and then write a loop, there are several directions to loop several layers, write in the loop to judge whether it has crossed the boundary and whether it meets the requirements, if not, continue to recurse, the code is as follows

bool pd(int x,int y)
{
	if(x<1||x>n||y<1||y>m)
	{
		return false;
	}
	if(vis[x][y])
	{
		return false;
	}
	return true;
}
void dfs(int x, int y)
{
    vis[x][y] = 1;
    for(int i=0;i<4;i++)
	{
		int xx = x+dx[i];
		int yy = y+dy[i];
        if(pd(xx,yy)&&s[xx][yy]=='.')
        {
        	dfs(x+xx[i],y+yy[i]);
		}
    }
}

The fourth step is to save the answer output, which is very simple, we will not put the code.

To sum up, we have learned a code template for Unicom block dfs. When we encounter the problem of Unicom block, we can use these four steps to solve it properly. Let’s take a look and record these four steps first, and then we will do two To consolidate it!

Exercise 1: Naval Battles

Topic description

During the summit, the armed forces are on high alert. The police will monitor every street, the military will guard buildings, and the airspace will be filled with F-2003 aircraft. In addition, cruisers and fleets will be sent to protect the coastline. Unfortunately for a variety of reasons, the Defense Admiralty has only a few officers capable of commanding large naval battles. So, they considered training some new naval commanders, and they chose the "Sea Battle" game to help with their learning.

In this famous game, a fixed number and shape of ships are placed on a square plate, each of which cannot touch the others. In this problem, we only consider boats to be square, all boats are squares composed of figures. Write a program to find the total number of ships placed on the board.

input format

The first line of the input file consists of two integers R and C separated by spaces, 1<=R, C<=1000, these two numbers represent the number of rows and columns of the game board respectively. The next R lines each contain C characters, each of which can be either "#" or ".", where "#" represents a part of a boat, and "." represents water.

output format

Output one line of the solution for each paragraph. If the position of the ships is correct (that is, there are only squares on the board that cannot touch each other, if two "#" signs are next to each other up and down or left and right but belong to two different ships, the two ships are called contacted each other). Just output a sentence "There are S ships.", S represents the number of ships. Otherwise output "Bad placement.".

6 8
.....#.#
##.....#
##.....#
.......#
#......#
#..#...#

The above is the simplest problem of judging connected blocks. We directly apply the four-step method. The first step is to save the map, the direction, and the mark.

Because the title requires four directions, a two-digit array, so we just press the above to open.

Code:

#include<bits/stdc++.h>
using namespace std;
const int N = 1001;
int dx[] = {1,0,0,-1};
int dy[] = {0,1,-1,0};
char s[N][N];
bool vis[N][N];
int main()
{
	int r,c;
	cin>>r>>c;
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		{
			cin>>s[i][j];
		}
	}
	return 0;
}

Then is our second step, find the starting point, the subject requirements, and start dfs

The title requires that there can be no adjacent ships. The meaning of the title is that if there are three hulls in a 2*2 grid, it is adjacent, so it is wrong. You need to write a function to judge independently. The starting point is any one encountered. Walked hull.

bool pd(int a,int b)
{
	int sum = 0;
	if(s[a][b]=='#')
	{
		sum++;
	}
	if(s[a+1][b]=='#')
	{
		sum++;
	}
	if(s[a][b+1]=='#')
	{
		sum++;
	}
	if(s[a+1][b+1]=='#')
	{
		sum++;
	}
	if(sum==3)
	{
		return false;
	}
	return true;
}

This is under the judgment function, in the four directions of the lower right and the right, to determine whether there is a bomb.

Then there is our code to find the starting point

for(int i=1;i<=r;i++)
{
	for(int j=1;j<=c;j++)
	{
		if(s[i][j]=='#'&&vis[i][j]==0)
		{
			dfs(i,j);
		}
	}
}

Find the hull# and start a search.

Then comes our third step, writing dfs.

How to write dfs, remember what we said above, cross the border, walk or not, cycle.

bool yuejie(int x,int y)
{
	if(x<1||x>r||y<1||y>c)
	{
		return false;
	}
	if(vis[x][y])
	{
		return false;
	}
	return true;
}
void dfs(int x,int y)
{
	vis[x][y] = 1;
	for(int i=0;i<4;i++)
	{
		int xx = x+dx[i];
		int yy = y+dy[i];
		if(yuejie(xx,yy)&&s[xx][yy]=='#')
		{
			dfs(xx,yy);
		}
	}
}

The fourth step is our answer. We first judge whether the ship is bombed, and then define a variable. Every time we enter the China Unicom block, it will be +1. If the bombing of the ship ends directly, there is no need to judge.

The complete code is as follows

#include<bits/stdc++.h>
using namespace std;
const int N = 1001;
int dx[] = {1,0,0,-1};
int dy[] = {0,1,-1,0};
char s[N][N];
bool vis[N][N];
int r,c;
int num;
bool yuejie(int x,int y)
{
	if(x<1||x>r||y<1||y>c)
	{
		return false;
	}
	if(vis[x][y])
	{
		return false;
	}
	return true;
}
void dfs(int x,int y)
{
	vis[x][y] = 1;
	for(int i=0;i<4;i++)
	{
		int xx = x+dx[i];
		int yy = y+dy[i];
		if(yuejie(xx,yy)&&s[xx][yy]=='#')
		{
			dfs(xx,yy);
		}
	}
}
bool pd(int a,int b)
{
	int sum = 0;
	if(s[a][b]=='#')
	{
		sum++;
	}
	if(s[a+1][b]=='#')
	{
		sum++;
	}
	if(s[a][b+1]=='#')
	{
		sum++;
	}
	if(s[a+1][b+1]=='#')
	{
		sum++;
	}
	if(sum==3)
	{
		return false;
	}
	return true;
}
int main()
{
	cin>>r>>c;
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		{
			cin>>s[i][j];
		}
	}
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		{
			if(pd(i,j)==false)
			{
				cout<<"Bad placement.";
				return 0;
			}
		}
	}
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		{
			if(s[i][j]=='#'&&vis[i][j]==0)
			{
				num++;
				dfs(i,j);
			}
		}
	}
	printf("There are %d ships.",num);
	return 0;
}

Direct AC! In fact, this code can be used without vis, so that the amount of code is smaller. You can think about writing it yourself.

ps: Modify the value of the original image

If you follow along, you should understand that if you solve the dfs of China Unicom block, I have prepared a few questions, you must contact me, remember my four-step method and solve it by yourself, you will solve a dfs yourself. !

Luogu: P1451 Find the number of cells - Luogu | New Ecology of Computer Science Education (luogu.com.cn)

P1596 [USACO10OCT]Lake Counting S - Luogu | New Ecology of Computer Science Education (luogu.com.cn)

The questions are not difficult, just type it out for yourself!

And then there's our full array.

Full permutation is also a four-step method, here is the most classic full permutation problem to explain

Exercise 2: Arrangement

Topic description

Output all non-repeated permutations of the natural numbers 1 to n in lexicographical order, that is, the full permutation of n, requiring that no repeated numbers appear in any generated sequence of numbers.

input format

An integer nn.

output format

All unique sequences of numbers consisting of 1∼n, one sequence per line.

5 field widths are reserved for each number.

Seeing this question, many people laughed. This question is also very simple. Here are the four-step method.

The first step, we don't have the direction array, is to judge whether it has been used and store the value array.

int n,pd[100],a[100];

The second step, find the starting point, the title requirements, start dfs

The starting point is naturally 0, and then search directly.

int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

The third step, write the dfs function

The question requirement is n, so we must first judge whether the question requirement is met, and then output and return, if not, then search down, because the question requires n, so the loop ends with =n, and each time we judge whether the number is useful or not However, if we don't use it, we save it, and then write a simple memoized search, because it will be messy if we don't clean up the scene when we return after use.

For example, if you use 123456, if you do not return to 0, then the next loop will judge that your array is still 123456, which will cause some data errors.

void dfs(int k)
{
    if(k==n)
    {
        for(int i=1;i<=n;i++)
        {
            printf("%5d",a[i]);
        }
        printf("\n");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(!pd[i])
        {
            pd[i]=1;
            a[k+1]=i;
            dfs(k+1);
            pd[i]=0;
        }
    }
}

The fourth step is ours! Ha ha ha ha

The complete code is as follows

#include<bits/stdc++.h>
using namespace std;
int n,pd[100],a[100];
void dfs(int k)
{
    if(k==n)
    {
        for(int i=1;i<=n;i++)
        {
            printf("%5d",a[i]);
        }
        printf("\n");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(!pd[i])
        {
            pd[i]=1;
            a[k+1]=i;
            dfs(k+1);
            pd[i]=0;
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

There are still two practice questions here. You can practice it yourself after class, and you will be able to master one!

Luogu: P1036 [NOIP2002 Popularization Group] Selection - Luogu | New Ecology of Computer Science Education (luogu.com.cn)

P1157 Combination Output - Luogu | New Ecology of Computer Science Education (luogu.com.cn)

Summarize

Today we learned about the connection block judgment and full arrangement judgment of dfs. These are commonly used. Other variants require our flexibility. How to write 4. The full arrangement of the answer output is: 1. Save the answer to judge 2. The starting point dfs3. How to write the dfs function 4. The answer output. These two methods are actually similar, that is, the whole arrangement has no direction, and more is the judgment of whether the number is used or not. Everyone should keep it in mind before you can break the dfs! 

Guess you like

Origin blog.csdn.net/qq_45400861/article/details/124082034