栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

迷宫问题(BFS, DFS)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

迷宫问题(BFS, DFS)

The Core Thoughts

核心思想

  • DFS (Depth First Search):
  • 深度优先搜索

      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.

      使用栈保存可以通过的路径(只要如果目前可以通过,则将该位置压栈)。 当无路可走时,再通过回溯回到尚未搜索到的路径。 如果回溯到栈为空时还没有结果,则无解。

  • BFS (Breadth First Search):
  • 广度优先搜索

      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

    分析

  • DFS (Depth First Search):
  • 深度优先搜索

    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.

    缺点:不能直接找到最短路径。

  • BFS (Breadth First Search):
  • 广度优先搜索

    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.

  • 转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/768999.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号