The Core Thoughts
核心思想
Save the path that can go through using Stack (if it can go through at present, push it to the Stack). When there is no way to go, then go back to the path that has not yet been searched through backtracking. If there is no result when backtracking until the Stack is empty, there is no solution.
使用栈保存可以通过的路径(只要如果目前可以通过,则将该位置压栈)。 当无路可走时,再通过回溯回到尚未搜索到的路径。 如果回溯到栈为空时还没有结果,则无解。
Use the queue to save all the traversable positions and expand the traversable routes in the queue layer by layer until it reaches the exit position. If the last queue is empty, there is no solution.
使用队列保存所有的可遍历位置,将队列中的可遍历路径逐层展开,直到到达出口位置。 如果最后队列为空,则无解。
Source Code
源代码
#include#include #include #include #include using namespace std; struct Box { int x; int y; int nextDirection; Box(int x, int y, int nextDirection) : x(x), y(y), nextDirection(nextDirection) {}; }; struct Box_1 { int x; int y; Box_1* prior; // The pointer to the prior point Box_1(int x, int y, Box_1* prior) : x(x), y(y), prior(prior) {}; }; vector > GenerateMaze() { int row, col; cout << "The number of rows and columns:" << endl; cin >> row >> col; cout << "Input the maze:" << endl; // The maze should be expanded by 2 lengths to comprise the frame of the maze vector > Maze(row + 2, vector (col + 2, 1)); for (int i = 1; i < row + 1; i++) { for (int j = 1; j < col + 1; j++) { cin >> Maze[i][j]; } } return Maze; } bool IsValidPosition(int x, int y, vector > Maze) { // Verify whether the initial and exit position is valid if (x <= 0 || y <= 0 || Maze[x][y] == 1) { cout << "Invaild postion!" << endl; return false; } else { return true; } } bool SetThePosition(vector > Maze, int& x, int& y, int& desX, int& desY) { cout << "The initial position:" << endl; cin >> x >> y; if (!(IsValidPosition(x, y, Maze))) { return false; } cout << "The exit position:" << endl; cin >> desX >> desY; if (!(IsValidPosition(desX, desY, Maze))) { return false; } return true; } bool Solution_DFS(Box& entity, stack & Path, vector >& Maze) { int desX, desY; // The index of the exit point if (!SetThePosition(Maze, entity.x, entity.y, desX, desY)) { return false; } Path.push(entity); Maze[entity.x][entity.y] = -1; // Set the position that has been visited is -1 to avoid endless loop while (!Path.empty()) { if (Path.top().x == desX && Path.top().y == desY) { // If the entity reaches the destination, return true return true; } entity = Path.top(); // Update the current position (where the entity arrived) Box temp = entity; // Define a temporary entity for seeking the path bool pathFound = false; // Before a new path is found, the flag is false while (temp.nextDirection <= 4 && !pathFound) { // Search a new path in four directions switch (temp.nextDirection) { case 1: temp.x++; break; case 2: temp.y++; break; case 3: temp.x--; break; case 4: temp.y--; break; } temp.nextDirection++; int direction = temp.nextDirection; // Reserve the direction for the next search if (Maze[temp.x][temp.y] == 0) { // If a new path is found pathFound = true; Maze[temp.x][temp.y] = -1; // Occupy the position Path.top().nextDirection = temp.nextDirection; // Save the direction temp.nextDirection = 1; // Reset the direction to 1 for the next search Path.push(temp); // Add the new path to the whole path } else { temp = entity; // Reset to the intial position temp.nextDirection = direction; // Save the last searching direction } } if (!pathFound) { // If the new path cannot be found Path.pop(); // pop the top element, keeping searching in the previous position Maze[entity.x][entity.y] = 0; // Recover the position that has been occupied } } return false; // If no path towards the destination can be found, return false to declare that the search fails } bool Solution_BFS(Box_1& entity, queue & Path, vector >& Maze) { int desX, desY; if (!SetThePosition(Maze, entity.x, entity.y, desX, desY)) { return false; } Path.push(entity); Maze[entity.x][entity.y] = -1; if (entity.x == desX && entity.y == desY) { return true; } while (!Path.empty()) { entity = Path.front(); Box_1* front = new Box_1(entity.x, entity.y, entity.prior); // Allocate memory for the front element so that the paths can be connected Box_1 temp = entity; int direction = 1; while (direction <= 4) { switch (direction) { case 1: temp.x++; break; case 2: temp.y++; break; case 3: temp.x--; break; case 4: temp.y--; break; } direction++; if (Maze[temp.x][temp.y] == 0) { Maze[temp.x][temp.y] = -1; temp.prior = front; // Connect with the prior path Path.push(temp); if (temp.x == desX && temp.y == desY) { return true; } } temp = entity; } Path.pop(); } return false; } void DisplayThePath_DFS(vector > Maze) { for (int i = 0; i < Maze.size(); i++) { for (int j = 0; j < Maze[i].size(); j++) { if (Maze[i][j] == 1) { cout << "O "; } else if (Maze[i][j] == 0) { cout << " "; } else if (Maze[i][j] == -1) { cout << "* "; } } cout << endl; } } void DisplayThePath_BFS(vector > Maze, Box_1* index) { while (index != nullptr) { Maze[index->x][index->y] = -1; index = index->prior; } for (int i = 0; i < Maze.size(); i++) { for (int j = 0; j < Maze[i].size(); j++) { if (Maze[i][j] == 1) { cout << "O "; } else if (Maze[i][j] == 0) { cout << " "; } else if (Maze[i][j] == -1) { cout << "* "; } } cout << endl; } return; } void PrintThePath_DFS(stack Path) { Box i(0, 0, 0); vector buf(Path.size(), i); for (int j = Path.size() - 1; j >= 0; j--) { buf[j] = Path.top(); Path.pop(); } cout << "The path is:" << endl; for (Box i : buf) { cout << '(' << i.x << ',' << i.y << ')' << endl; } return; } void PrintThePath_BFS(Box_1 *path) { Box_1* index = path; stack temp; while (index != nullptr) { temp.push(*index); index = index->prior; } while (!temp.empty()) { cout << '(' << temp.top().x << ',' << temp.top().y << ')' << endl; temp.pop(); } } int main() { Box entity(0, 0, 1); stack Path; vector > Maze = GenerateMaze(); if (Solution_DFS(entity, Path, Maze)) { PrintThePath_DFS(Path); DisplayThePath_DFS(Maze); } else { cout << "No path found!" << endl; } Box_1 entity_1(0, 0, nullptr); vector > Maze_1 = GenerateMaze(); vector > temp = Maze_1; queue Path_1; if (Solution_BFS(entity_1, Path_1, Maze_1)) { DisplayThePath_BFS(temp, &Path_1.back()); PrintThePath_BFS(&Path_1.back()); } else { cout << "No path found!" << endl; } return 0; }
Analysis
分析
Traits: All the paths are found, and it uses backtracking, saves the location in each search and goes deeper, and when it's done, it goes back to the next location, until it has searched all the deepest locations (These traits can be manifested typically in Trees traversal).
特点:使用回溯。在每次搜索中保存位置并继续深入,完成后,回溯下一个位置,直到搜索完所有最深的位置(这些特征可以很典型体现在树遍历)。
Pros: There is no need to record precursor nodes like breadth-first search, which will occupy extra space especially when the problem’s scale is very large.
优点:不需要像广度优先搜索那样记录前驱节点,这会占用额外的空间,尤其是当问题规模很大时。
Cons: Cannot find the shortest path directly.
缺点:不能直接找到最短路径。
Traits: Starting from a chosen point, then take one step at a time from each direction of the point to the end (i.e. continue in the next direction after taking one step in one direction). If it can't find the solution, it returns the predetermined value. If it can find the solution, it returns the desired solution.
特点:从选定的点开始,然后从该点的每个方向一步一步到终点(即在一个方向上迈出一步后继续下一个方向)。 如果找不到解,则返回预定值。 如果它可以找到解决方案,它会返回所需的解决方案。
Pros: The path found is the shortest path.
优点:找到的路径即是最短路径。
Cons: Records of the precursor nodes is needed.
缺点:需要记录前驱节点。
Personal Experience
After implementing this algorithm, not only have I learned some new knowledge, but deepened and upgraded the knowledge I have already known. The core of this algorithm is the two ways of searching (BFS and DFS) and two data structures (Stack and Queue) that are used to implement them. To implement this algorithm, I used two ways of traversal (also BFS and DFS) in Binary Trees as the analogy. The idea of solving this problem is relatively simple, but there were numerous problems in the implementation (such as how to record the precursor nodes in BFS solution, how to implement the searching process, etc.), which took me a lot of work and time. Nevertheless, the whole process paid off, especially when I was trying to comprehend the ingenuity and beauty of this algorithm.



