如何在BFS算法中计算移动?(迷宫中的最短路径)

How to count moves in BFS algorithm? (Shortest path in a maze)

本文关键字:迷宫 最短路径 计算 BFS 算法 移动      更新时间:2023-10-16

所以我尝试实现BFS算法并真正了解它是如何工作的(从头开始创建某种"我的版本",只是看图形和一些伪代码),这是我最终得到的:

#include<iostream>
#include<string>
#include<fstream>
#include<queue>
using namespace std;

    void main(int argc, char *argv[])
    {
        // Deklaracja uchwytu do pliku (tylko do odczytu pliku)
        ifstream plik(argv[1]);
        // Tablica stringow - przechowujaca wartosci pol 12x12
        string labirynt[12];
        pair <int, int> start;
        pair <int, int> koniec;
        // Wektor par - działa jak tablica, przechowuje pary współrzędnych pól
        queue <pair<int, int>> kolejka;
        // Tablica odwiedzin - sprawdza czy pole zostalo odwiedzone, 0 jesli nie, 1 jesli tak
        bool odwiedzone[12][12] = { 0 };
        // Zmienna pomocnicza - bo getline sluzy do umieszczania danych w stringu, nie w tablicy znakow
        int i = 0;
        // Pętla wczytująca tekst z pliku do tablicy labirynt
        while (getline(plik, labirynt[i]))
        {
            i++;
        }
        // Wyszukanie początku i końca w labiryncie (A i B)
        for (int i = 0; i < 12; i++)
        {
            for (int j = 0; j < 12; j++)
            {
                if (labirynt[i][j] == 'A')
                {
                    start.first = i;
                    start.second = j;
                }
                if (labirynt[i][j] == 'B')
                {
                    koniec.first = i;
                    koniec.second = j;
                }
            }
        }

        // Ustawiamy pole startowe jako odwiedzone - żadne pole nie może być odwiedzone więcej niż 1 raz
        odwiedzone[start.first][start.second] = true;

        // Wiersz i kolumna bieżącego wierzchołka
        int w, k;


        kolejka.push(start);
        // Dopóki kolejka nie jest pusta
        while (!kolejka.empty())
        {
            // Pobieramy z kolejki wiersz i kolumnę bieżącego wierzchołka
            w = kolejka.front().first;
            k = kolejka.front().second;
            // Usuwamy parę z kolejki
            kolejka.pop();

            // Sprawdzamy czy dotarliśmy do wyjścia
            if (w == koniec.first && k == koniec.second)
                break;
            // Przeglądamy sąsiadów bieżącego wierzchołka
            for (i = -1; i <= 1; i++)
            for (int j = -1; j <= 1; j++)
            {
                if ((i != j) && (!i || !j))
                if (labirynt[w + i][k + j] == ' ' && !odwiedzone[w + i][k + j])
                {
                    odwiedzone[w + i][k + j] = true;
                    pair <int, int> para;
                    para.first = w + i;
                    para.second = k + j;
                    kolejka.push(para);
                    cout << kolejka.front().first << endl;
                    cout << kolejka.front().second << endl;
                }
            }

        }
    system("PAUSE");
    }

这是我使用的示例迷宫(程序从.exe上放置的文件读取)

xxxxxxxxxxxx
xxA  xxxxxxx
xx x  xxxxxx
x  x  xxxxxx
xx x    xxxx
xx xxx xxxxx
x   xxxxxxxx
x x  xxxxxxx
x xxx xxxxxx
x    xxxxxxx
xxx     Bxxx
xxxxxxxxxxxx

有效(显示它穿过的迷宫中每个字段的坐标并找到 B),但我不知道如何计算通过最短路径所需的移动。

不要使用

odwiedzone[w + i][k + j] = true; 来检查之前是否步进的坐标,而是使用 odwiedzone[w + i][k + j] = now + 1 之类的东西来计算从开始到该位置的步数:

// first, declare all odwiedzone[][]=-1
...
odwiedzone[start.first][start.second] = 0;
// first position needs 0 step
...
            for (i = -1; i <= 1; i++)
            for (int j = -1; j <= 1; j++)
            {
                if ((i != j) && (!i || !j))
                if (labirynt[w + i][k + j] == ' ' && odwiedzone[w + i][k + j]==-1)
                {
                    odwiedzone[w + i][k + j] = odwiedzone[w][k]+1;
                    //next position = now position + 1
                    pair <int, int> para;
                    para.first = w + i;
                    para.second = k + j;
                    kolejka.push(para);
                    cout << kolejka.front().first << endl;
                    cout << kolejka.front().second << endl;
                }
            }

我看到了两种实现您想要的方法:

  1. 使用单独的队列来存储与每个单元格的关联距离,例如,start 将具有 0,start 的每个相邻项将具有 1,依此类推。每次添加新邻居时,他的值将是到当前单元格的距离 + 1。第二个队列中目标的值将为您提供路径长度。

  2. 在队列中添加邻居时,记录他的父级。因此,当您找到源时,您可以重建路径并计算步数。