Depth first search (DFS)

Posted by mathewvp on Sun, 21 Nov 2021 10:20:19 +0100

Depth first search:

Starting from the initial state, there may be multiple states in the next step; Select one of the States to go deep and reach a new state; Until you can't go further, go back to the previous step, move to another state, and then go further. Finally, all the attainable states are traversed and the final solution is obtained.

1. The DFS code is much shorter than that of breadth first search (BFS). Take a classic search question

hdu 1312 Red and Black

describe

There is a rectangular house with square tiles of red and black on the ground. You stand on one of the black tiles and can only move to the adjacent black tiles. Please write a program to calculate how many black tiles you can reach.

input

Includes multiple data sets. The first row of each data set is two integers W and H, representing the number of tiles in the x direction and y direction, respectively. Neither w nor H exceeds 20. In the next H lines, each line includes w characters. Each character represents the color of a tile. The rules are as follows
1) '.': black ceramic tile;
2) '#': white tiles;
3) '@': black tile, and you stand on this tile. This character appears only once in each data set.
When two zeros are read in one line, it indicates the end of input.

output

For each data set, output a row to show the number of tiles you can reach from the initial position (including the tiles at the initial position when counting).

sample input

6 9 
....#. 
.....# 
...... 
...... 
...... 
...... 
...... 
#@...# 
.#..#. 
0 0

sample output

45

Idea:

Both BFS and DFS can be used in this problem, and the idea is very simple. As long as there is a way, go down. If there is no way, go back to the previous step and continue in another direction until you can't go. The method code of DFS for this problem is much shorter.

The code is as follows:

1, BFS

#include <iostream>
#include <queue>
using namespace std;
char room[23][23];
int dir[4][2] = {
	{-1,0},      //towards the left
	{0,-1},      //Up
	{1,0},       //towards the right
	{0,1}        //down
};
int Wx, Hy, num;       //Row Wx and column Hy use num to count the number of walkable positions
#Define check (x, y) (x < Wx & & x > = 0 & & Y > = 0 & & Y < HY) / / is it in room
struct node { int x, y; };
void BFS(int dx, int dy) {
	num = 1;
	queue<node>q;    //Place coordinate points in the queue
	node start, next;
	start.x = dx;
	start.y = dy;
	q.push(start);
	while (!q.empty()) {
		start = q.front();
		q.pop();
		//cout <<"out"<<start.x<<start,y<<endl;
		for (int i = 0; i < 4; i++) {    //Search one by one clockwise in the left, upper, right and lower directions
			next.x = start.x + dir[i][0];
			next.y = start.y + dir[i][1];
			if (CHECK(next.x, next.y) && room[next.x][next.y] == '.') {
				room[next.x][next.y] = '#';       // Mark as processed after entering the team
				num++;
				q.push(next);
			}	
		}
	}
}
int main() {
	int x, y, dx, dy;
	while (cin >> Wx >> Hy) {            //Row Wx, column Hy
		if (Wx == 0 && Hy == 0)          //end
			break;
		for (y = 0; y < Hy; y++) {      //With Hy column
			for (x = 0; x < Wx; x++) {   //Read in one line at a time
				cin >> room[x][y];
				if (room[x][y] == '@') { //Read in starting point
					dx = x;
					dy = y;
				}
			}
		}
		num = 0;
		BFS(dx, dy);
		cout << num << endl;
	}
	return 0;
}

2, DFS

#include <iostream>
using namespace std;
int  Wx, Hy;
int num;
char room[23][23];
#define CHECK(x,y) (x>=0&&x<Wx&&y>=0&&y<Hy)
int dir[4][2] = { {-1,0},{0,-1},{1,0},{0,1} };
void dfs(int dx, int dy)
{
	room[dx][dy] = '#';
	num++;

	for (int i = 0; i < 4; i++)
	{
		int newx = dx + dir[i][0];
		int newy = dy + dir[i][1];
		if (CHECK(newx, newy) && room[newx][newy] == '.')
		{
			dfs(newx, newy);
		}
	}
}
int main()
{
	int dx, dy, x, y;
	while (cin >> Wx >> Hy) {
		if (Wx == 0 && Hy == 0)
			break;

		for (y = 0; y < Hy; y++)
		{
			for (x = 0; x < Wx; x++)
			{
				cin >> room[x][y];
				if (room[x][y] == '@')
				{
					dx = x;
					dy = y;
				}
			}
		}
		num = 0;
		dfs(dx, dy);
		cout << num << endl;
	}
	return 0;
}

The main functions of the two methods are the same. In contrast, it can be seen that the code written in DFS is much shorter, but I think BFS is better understood

2. There is an inconvenient place for DFS: because the recursive listing of all paths may timeout because the number is too large. Because many nodes do not meet the conditions, you need to use "backtracking", that is, "retreat when you see the wrong head", stop and return halfway. The following questions are examples

poj 2488 A Knight's Journey

describe

background
The knight was tired of seeing the same black and white squares over and over again and decided
travel round the world. Whenever a knight moves, it is two squares in one direction and a square perpendicular to this direction. The knight's world is the chessboard on which he lives. Our knight lives on a chessboard. The area of the chessboard is smaller than the ordinary 8 * 8 chessboard, but it is still rectangular. Can you help this adventurous Knight make travel plans?

problem
Find a path for the knight to visit each square once. Knights can start and end in any square on the chessboard.

input

The input starts with a positive integer n on the first line. The following lines contain n test cases. Each test case consists of a line containing two positive integers P and Q, so that 1 < = P * q < = 26. This represents the ap * q chessboard, where p describes how many different squares 1  . , P exists, Q describes how many different square letters exist. These are the first Q letters of the Latin alphabet: A  . .

output

The output of each scene starts with a line containing "Scenario #i:", where I is the scene number starting from 1. Then print a line containing the first path to access all squares of the chessboard in dictionary order, and then the knight moves by an empty line. The path should be given in one line by the name of the block accessed through the connection. Each box name consists of a capital letter followed by a number.
If such a path does not exist, you should output impossible on one line.

sample input

3
1 1
2 3
4 3

sample output

Scenario #1:
A1

Scenario #2:
impossible

Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4

  Idea:

Choose any starting point and jump the whole chessboard without repetition according to the jumping method of the chess horse. If there are multiple routes, choose the route with the smallest dictionary order (the route is the set of horizontal and vertical coordinates of points. Note that the horizontal coordinates of the chessboard are in capital letters and the vertical coordinates are numbers)

First of all, we should understand that the meaning of this question is whether we can only walk once (without looking back and repeating) After walking the whole map, the ordinary depth first search is to go all the way, and then go back to a place along the road to continue the deep search. Therefore, the backtracking idea used in this problem is that if we don't walk again, we will finish walking, make a mark, and the algorithm will stop; otherwise, when we go to a certain step under a DFS, there is no way to walk according to the rules of horse jumping, and there are points on the chessboard for walking, so we can You need to undo this step and try other routes (of course, other routes may also lead to revocation). The so-called undo step is to reset the point when the recursive deep search returns, so that when the current route does not work and another route is changed, the state of the point is not accessed, rather than being treated as accessed like ordinary DFS.

The code is as follows:

#include <stdio.h>	
#include <string.h>
#include <iostream>
using namespace std;
int book[10][10];
int arr[8][2] = { {-1,-2},{1,-2},{-2,-1},{2,-1},{-2,1},{2,1},{-1,2},{1,2} };//Eight directions,
//According to the position of the horse on the way, because it is a dictionary order, it must go to the upper left corner first, so the left of these eight directions takes precedence
int a, b;
int res[100][2];//What is the first step to save xy
int found;//Found a flag that can execute the channel
#define check(x,y) (x < 0 || x >= a || y < 0 || y >= b)		
void dfs(int m, int n, int depth)
{
	res[depth][0] = m;
	res[depth][1] = n;
	if (depth == a * b)
	{
		found = 1;
		for (int i = 1; i <= a * b; i++)
		{
			printf("%c%d", res[i][1] + 'A', res[i][0] + 1);
		}
		cout << endl;
		return;
	}
	int k;
	int tx, ty;
	for (k = 0; k < 8; k++)
	{
		tx = m + arr[k][0];
		ty = n + arr[k][1];
		if (check(tx,ty)||book[tx][ty] != 0)
			continue;
		if (found)
			break;
		book[tx][ty] = 1;
		dfs(tx, ty, depth + 1);
		book[tx][ty] = 0;
	}
}

int main()
{
	int n;
	cin >> n;
	int count = 0;
	while (n--)
	{
		memset(book, 0, sizeof(book));
		found = 0;
		count++;
		cin >> a >> b;
		cout << "Scenario #" << count << ":" << endl;
		book[0][0] = 1;
		dfs(0, 0, 1);
		if (!found)
		{
			cout << "impossible" << endl;
		}
		if (n != 0)
			cout << endl;
	}
}

Big data liyang

Topics: C++ Algorithm