C++ depth-first search detailed

content

hello

What is dfs?

DFS algorithm process:

dfs basic framework

Topic 1

code

Topic 2 n-queens problem

code

navigate

 code

At last


hello

Hello, everyone

Get up from the sofa at night and sit in front of the computer

I'm probably bored

After thinking about it, I still wrote a detailed explanation of c++ depth-first search (DFS)

It's easy, but there's also the shadow of violence

As the saying goes: the violent search hangs on the machine, and the watch is out of the province. Partially divide the examples, and violence produces miracles.

What is dfs?

DFS (Depth First Search)  , that is,  depth first search  , is a way of traversing the graph.

For example, this picture (writing numbers with the mouse is a bit ugly)

We want to find the value of 4

Suppose we start from 1

1 not found

Looking for 2 again, 2 can't be found,

Looking for 3, 3 but not found

Found out that it's over

Step by step back to 1, go another way, and find 4

To sum up, dfs will preferentially visit the child nodes starting from the changed point when searching for a new point, and backtrack after all child nodes are accessed. It can be seen that dfs and recursion have the same goal.
On the contrary, there is BFS (Breath First Search) breadth-first search. When using bfs to access the above example, the access order is: 1, 2, 4, 3. The program will visit all the child nodes of the current node and search down layer by layer.

Practice English:

DFS will preferentially visit the child nodes starting from the change point when searching for a new point, and backtrack after all the child nodes are accessed. It can be seen that DFS and recursion come to the same destination.
In contrast, Breath First Search (BFS) is the breadth-first Search. When BFS is used to access the above example, the access sequence is 1,2,4,3. The program accesses all the children of the current node, level by level down.

understand? It's that simple

DFS algorithm process:

1. Choose a vertex as the starting point v, visit the vertex
2. In the depth direction, traverse the unvisited adjacent points of v in turn - until the end of this traversal
3. After one traversal, if there are unvisited vertices: choose one The vertex is not visited as the starting point, the second step of GOTO

dfs basic framework

The basic writing code is like this

void dfs(int u){//u:当前节点
	vis[u]=true;
	for(int& v:g[u]){//访问u连到的每个节点
		if(!vis[v]) dfs(v);
	}
}

In fact, it has very little code, mainly to understand

It's that simple, look at the topic

Topic 1

The idea is actually relatively simple, a bit similar to the exhaustive method. We build a number, and each layer adds a number without enumeration in turn. When the bottom layer is reached, it is an answer.

For example, we first fill in 1 for the first number, and then continue to go deeper to the next layer because there are still numbers left unfilled. Next level Since the first number 1 has been enumerated, we enumerate the second number 2. Then continue to enter the third layer and enumerate the third number 3. Since all the numbers have been enumerated, we need to perform a backtracking at this time to return to the second layer. Since there is only one number in the second layer that is not enumerated, we have enumerated all the possibilities of the second layer, so we go back to the first layer. Next, fill the second position with an unenumerated 3, and repeat.

code

#include<bits/stdc++.h>

using namespace std;

const int N = 10;

//用一个path数组来存储每次到底层的路径 
int path[N];
//用一个布尔数组来存储每次已经遍历的点,默认是false 
bool st[N];
int n;

//u表示当前的层数 
void dfs(int u)
{
    //当已经到达最底层了,溯回并输出路径 
    if( u == n )
    {
        for(int i = 0 ; i < n ; i++) printf("%d " , path[i] );
        //作用跟printf("%s\n",s),默认帮你换行 
        puts("");
        //溯回上一层 
        return;
    }
    else
    {
        //这里从第一个数开始循环 
        for(int i = 1; i <= n ; i++)
        {
            //如果该数字未被访问,就使用 
            if( !st[i] )
            {
                path[u] = i;
                //标记第i个数已经被使用 
                st[i] = true;
                //进入下一层 
                dfs( u + 1 );
                //还原现场 
                st[i] = false; 
            }
        }
    }

}

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

Topic 2 n-queens problem

The title
n-queens problem refers to placing n queens on an n×n chess board so that the queens cannot attack each other, that is, no two queens can be in the same row, column or diagonal line.

1_597ec77c49-8-queens.png

Now given an integer n, please output all the chess pieces that satisfy the condition.

input format

A line containing the integer n.

output format

Each solution occupies n lines, and each line outputs a string of length n representing the complete board state.

Among them, . indicates that the square state of a certain position is empty, and Q indicates that a queen is placed on the square of a certain position.

After the output of each scheme is completed, a blank line is output.

Note: There must be no extra spaces at the end of the line.

The order of the output schemes is arbitrary, as long as there are no repetitions and no omissions.

data range

1≤n≤9

Input sample:

4


Sample output:

.Q..
...Q
Q...
..Q.
 
..Q.
Q...
...Q
.Q..

code

Analysis see code comments

#include<iostream>
 
using namespace std;
 
const int N = 20;//对角线的个数是2n - 1 
char g[N][N];//存储当前的图 
bool col[N], dg[N], udg[N];//列和对角线以及反对角线是否有皇后(true 有,false无) 
 
int n;
 
void dfs(int u)
{
	if(u == n)//表示已经搜了n行,故输出这条路径 
	{
		for(int i = 0; i < n; i ++)puts(g[i]);
		puts("");
		return;
	}
	
	for(int i = 0; i < n; i ++)
	{
		if(!col[i] && !dg[u + i] && !udg[n - u + i])//对角线为 n- u + i, 反对角线下标为 u + i 
		{
			g[u][i] = 'Q';
			col[i] = dg[u + i] = udg[n - u + i] = true;
			
			dfs(u + 1);
			//还原现场 
			col[i] = dg[u + i] = udg[n - u + i] = false;
			g[u][i] = '.';
		}
	}
}
 
int main()
{
	cin >> n;
	
	for(int i = 0; i < n; i ++)
		for(int j = 0; j < n; j ++)
			g[i][j] = '.';
			
	dfs(0);
	
	return 0;	
} 
//dfs与递归类似 

navigate

Okay, the idea is finished, and the topic is finished.

According to common sense, hehe, it's time for happy coding

I believe you have heard of or used wayfinding.

The main thing is to store the path through the stack, assist the map to change the direction and remember whether the path has been passed.

The effect ( the compiler I use is VS2019 ), there will be a # in the running program, it will move, move along the path I drew, and finally find the exit

 

 code

#include <iostream>
#include <stack>
#include <Windows.h>
using namespace std;
#define ROWS 12//x
#define COLS 12//y
struct MyPoint {
	int x;
	int y;
	//MyPoint(int xx, int yy) :x(xx), y(yy) {};
};
//辅助地图
enum dirent { p_up, p_left, p_down, p_right };
struct pathNode {
	int val;//
	dirent dir;	//方向
	bool	isFind;//是否走过

};

//打印地图
void printMap(int map[][12], MyPoint pos)
{
	system("cls");
	for (int i = 0; i < ROWS; i++)
	{
		for (int j = 0; j < COLS; j++)
		{
			if (i == pos.x && j == pos.y)
			{
				cout << "#";
			}
			else if (map[i][j])
			{
				cout << "*";
			}
			else
			{
				cout << " ";
			}
		}
		cout << endl;
	}
	Sleep(200);
}
int main()
{
	/*
	地图:  数组
	1墙  0路
	*/
	int map[ROWS][COLS] = {
		{1,1,1,1,1,1,1,1,1,1,1,1},
		{1,0,1,1,1,1,1,1,1,1,1,1},
		{1,0,1,1,0,1,1,1,1,1,1,1},
		{1,0,1,1,0,1,1,1,1,1,1,1},
		{1,0,1,1,0,1,1,0,0,0,0,1},
		{1,0,1,1,0,1,1,1,1,1,0,1},
		{1,0,0,0,0,0,0,0,1,1,0,1},
		{1,0,1,1,0,1,1,0,1,1,0,1},
		{1,0,1,1,0,1,1,0,1,1,0,1},
		{1,0,1,1,0,1,0,0,0,0,0,1},
		{1,0,1,1,0,1,0,1,1,1,0,1},
		{1,1,1,1,1,1,1,1,1,1,1,1}
	};
	MyPoint begPos = { 1,1 };
	MyPoint endPos = { 10,10 };
	//printMap(map,begPos);
	pathNode pathMap[ROWS][COLS] = { 0 };
	for (int i = 0; i < ROWS; i++)
		for (int j = 0; j < COLS; j++)
		{
			pathMap[i][j].val = map[i][j];
		}
	MyPoint currentPos = begPos;
	MyPoint searchPos; //试探点
	stack<MyPoint> stack;
	stack.push(begPos);
	pathMap[begPos.x][begPos.y].isFind = true;//标记走过

	bool isFindEnd = false;
	while (!isFindEnd)
	{
		printMap(map, currentPos);
		//确定试探点
		searchPos = currentPos;
		switch (pathMap[currentPos.x][currentPos.y].dir)
		{
		case p_up:
			searchPos.x--;
			pathMap[currentPos.x][currentPos.y].dir = p_left;
			break;
		case p_left:
			searchPos.y--;
			pathMap[currentPos.x][currentPos.y].dir = p_down;
			break;
		case p_down:
			searchPos.x++;
			pathMap[currentPos.x][currentPos.y].dir = p_right;
			break;
		case p_right:
			searchPos.y++;
			if (pathMap[searchPos.x][searchPos.y].val != 0 ||	//不是路
				pathMap[searchPos.x][searchPos.y].isFind == true) //以前路过
			{
				stack.pop();
				currentPos = stack.top();
			}
			break;
		}
		//判断试探点
		if (pathMap[searchPos.x][searchPos.y].val == 0 &&	//路
			pathMap[searchPos.x][searchPos.y].isFind == 0)	//未走过
		{

			currentPos = searchPos;
			//走
			//标记走过
			pathMap[currentPos.x][currentPos.y].isFind = true;
			//入栈
			stack.push(currentPos);
		}

		//判断是否终点
		if (currentPos.x == endPos.x &&
			currentPos.y == endPos.y)
			isFindEnd = true;
		//判断是否栈为空
		if (stack.empty())
		{
			cout << "未找到路径" << endl;
			break;
		}
	}
	//显示路径
	if (isFindEnd)
	{
		cout << "path:";
		while (!stack.empty())
		{
			cout << stack.top().x << "," << stack.top().y << endl;
			stack.pop();
		}
	}
	return 0;
}

At last

Alright, that's it for DFS

see you later!

Bye-Bye

Guess you like

Origin blog.csdn.net/m0_64036070/article/details/124258758