たそらぼ

日頃思ったこととかメモとか。

幅優先探索による迷路の探索

幅優先探索で迷路の最短ルート探索をしました。
色々ネットで調べて見たのですが、意外とピンとくるものがなかったため、備忘録として...。


例題としてはAtCoder幅優先探索の問題を使っています。
C - 幅優先探索
#ただし本質ではないステップ数をどうやって数えるかで、少し苦労しました。

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

//サイズが大きいため、Globalで宣言する。
//関数間での受け渡しも不要になる。
//step数の保存はsrcリストに格納する。
int R, C;
int sx, sy, gx, gy;
char c[55][55];
bool visited[55][55];
int src[55][55];
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
queue<int> xq;
queue<int> yq;

void init(){
/**
 *標準入力からの値の読み込み
 *Global変数の初期化
 */

    cin >> R >> C;
    cin >> sx >> sy;
    sx -= 1;
    sy -= 1;

    cin >> gx >> gy;
    gx -= 1;
    gy -= 1;

    for(int i = 0; i < R; ++i){
        for(int j = 0; j < C; ++j){
            cin >> c[i][j];
            visited[i][j] = false; 
        }
    }
    visited[0][0] = true;
    src[sx][sy] = 0;
}

int main(){
    //次のステップの位置
    int xNext, yNext;


    //値の読み込みと変数の初期化
    init();

    //スタート位置をqueueにpushする。
    //queueはxとyを別々に作る。
    xq.push(sx);
    yq.push(sy);

    //BFSのループ
    do{

        int xi = xq.front();
        int yi = yq.front();
        xq.pop();
        yq.pop();

        //dx,dyを使って上下左右を探索する。
        //'.'であればqueueに格納する。        
        for(int i = 0; i < 4; ++i){
            
            xNext = xi + dx[i];
            yNext = yi + dy[i];

            if(c[xNext][yNext] == '.' && !visited[xNext][yNext]){
                xq.push(xNext);
                yq.push(yNext);
                visited[xNext][yNext] = true;
                src[xNext][yNext] = src[xi][yi] + 1;

                //Goal時の処理
                if(xNext == gx && yNext == gy){
                    cout << src[xNext][yNext] << endl;
                    return 0;

                } 
            }
        }
    //x,yのqueueが共に空であれば終了する。
    }while(!xq.empty() || !yq.empty());

    return 0;
}

グラフのような1次元探索だとQueueが一つで済んで分かりやすいのですが、
2次元の迷路のようなものだとQueueが二つ必要なので直感的には少し分かりにくいなぁという感じ...。