Xinao 1215: maze (explain the restoration of tag array in detail)

Posted by t31os on Tue, 08 Feb 2022 17:34:13 +0100


1215: Maze
Time limit: 1000 ms memory limit: 65536 KB

[Title Description]
One day, while exploring in the forest, extende accidentally walked into a maze, which can be seen as a maze by n × n
Each grid point has only two states And #, the former means passable, and the latter means impassable. At the same time, when extend is at A grid point, he can only move to the adjacent grid point in one of the four directions of southeast and Northwest (or up, down, left and right). Extend wants to go from point A to point B and asks if he can do it without going out of the maze. If one of the starting point or the ending point is impassable (it is #), it is regarded as impossible.

[input]
The first line is the number of groups k of test data, followed by group k input. The first row of each group of test data is A positive integer n(1 ≤ n ≤ 100), indicating that the scale of the maze is n × N. Next is an n × N matrix, the elements in the matrix are Or #. The next line is four integers ha, la, hb and LB, describing that A is in row HA and column la, and B is in row hb and column lb. Note that ha, la, hb and LB are all counted from 0.

[output]
k lines, each line of output corresponds to an input. If it can be done, it will output "YES", otherwise it will output "NO".

Original writing (timeout)

At first, I didn't think much about it, so I used dfs to do it. The code is as follows:

#include<bits/stdc++.h>
using namespace std;

int k, n;
char a[105][105]; //Map 
int b[105][105]; //Tag array 
int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //Direction array 
int startx, starty, endx, endy;
bool flag;

void dfs(int x, int y) {
	//Recursive exit
	if (x == endx && y == endy) {
		cout << "YES" << endl;
		flag = true;
		return;
	}
	
	//Recursive condition
	for (int i = 0; i < 4; i++) {
		int nextx = x + d[i][0];
		int nexty = y + d[i][1];
		if (nextx >= 0 && nexty >= 0 && nextx < n && nexty < n && a[nextx][nexty] == '.' && !b[nextx][nexty]) {
			//Do not cross the border, no obstacles, no walking, and meet the three at the same time
			b[nextx][nexty] = 1;
			dfs(nextx, nexty);
			b[nextx][nexty] = 0; 
		}
	} 
}

int main()
{
	cin >> k;
	for (int i = 0; i < k; i++) {
		//Initialization work 
		memset(a, 0, sizeof(a)); 
		memset(b, 0, sizeof(b)); 
		
		//Enter map dimensions 
		cin >> n;
		
		//Input map
		for (int row = 0; row < n; row++) {
			for (int col = 0; col < n; col++) {
				cin >> a[row][col];
			}
		} 
		
		//Enter start and end points
		cin >> startx >> starty >> endx >> endy;
		
		//Special judgment
		if (a[startx][starty] == '#' || a[endx][endy] == '#') { //The start or end point is# 
			cout << "NO" << endl;
			continue;
		} 
		
		flag = false;
		b[startx][starty] = 1;
		dfs(startx, starty);
		if (flag == false) cout << "NO" << endl;
	}
	return 0;
}

It timed out

Summary of reasons for overtime writing

After communicating with the boss, it is found that there is no need to restore the tag array when tracing back. So the question is, why not restore the tag array?

Yes, when we first came into contact with the deep search backtracking algorithm, we often wrote such code:

//b is the tag array
b[x] = 1; //The mark has passed
dfs(); //Deep search
b[x] = 0; //Trace back and restore tag array

However, we should know that the requirements of the corresponding topics of this writing are generally as follows: "find the shortest path", "find the total number of schemes", "list all schemes", etc. This requires us to exhaust all the circumstances. For example, if we can't get through one way, we can go back, and after we go back, we can still go through this road in the future, because we have restored the tag array in the process of backtracking. In terms of image, we erase the memory of our journey here, so we may come here again in the future.

But for questions like this, we usually write as follows:

//b is the tag array
b[x] = 1; //The mark has passed
dfs(); //Deep search

The corresponding topics are generally "whether it can be reached", "whether there is a scheme that can be reached", etc. Because our goal is to find the end point, we don't need to exhaust all the schemes as above. As long as we find them, we will stop searching. For example, if we can't get through one road, then we go back, and on the way back, we fill these places with soil, and we won't go here in the future (if this road can't find the end, why should I go here in the future!?). Until we find the end, the search stops. The reason why it won't time out is that we fill in all the roads we have traveled, so we won't go again in the future, reducing the complexity.

Correct writing

In fact, b[nextx][nexty] = 0; Just comment it out.

#include<bits/stdc++.h>
using namespace std;

int k, n;
char a[105][105]; //Map 
int b[105][105]; //Tag array 
int d[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //Direction array 
int startx, starty, endx, endy;
bool flag;

void dfs(int x, int y) {
	//Recursive exit
	if (x == endx && y == endy) {
		cout << "YES" << endl;
		flag = true;
		return;
	}
	
	//Recursive condition
	for (int i = 0; i < 4; i++) {
		int nextx = x + d[i][0];
		int nexty = y + d[i][1];
		if (nextx >= 0 && nexty >= 0 && nextx < n && nexty < n && a[nextx][nexty] == '.' && !b[nextx][nexty]) {
			//Do not cross the border, no obstacles, no walking, and meet the three at the same time
			b[nextx][nexty] = 1;
			dfs(nextx, nexty);
			//b[nextx][nexty] = 0; 
		}
	} 
}

int main()
{
	cin >> k;
	for (int i = 0; i < k; i++) {
		//Initialization work 
		memset(a, 0, sizeof(a)); 
		memset(b, 0, sizeof(b)); 
		
		//Enter map dimensions 
		cin >> n;
		
		//Input map
		for (int row = 0; row < n; row++) {
			for (int col = 0; col < n; col++) {
				cin >> a[row][col];
			}
		} 
		
		//Enter start and end points
		cin >> startx >> starty >> endx >> endy;
		
		//Special judgment
		if (a[startx][starty] == '#' || a[endx][endy] == '#') { //The start or end point is# 
			cout << "NO" << endl;
			continue;
		} 
		
		flag = false;
		b[startx][starty] = 1;
		dfs(startx, starty);
		if (flag == false) cout << "NO" << endl;
	}
	return 0;
}

Topics: C++ Algorithm dfs