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

时间:2016-05-31 22:09:37

标签: c++ algorithm shortest-path breadth-first-search

所以我尝试实现一个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),但我不知道如何计算通过最短路径所需的移动。

2 个答案:

答案 0 :(得分:2)

而不是使用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 :(得分:1)

我看到了实现你想要的两种方式:

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

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