0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アルゴリズム力UP!『ATC 001 A 幅優先探索 』を解いてみよう

Last updated at Posted at 2020-12-20

記事を読むとわかること

  • 記事の作者の『ATC 001 A 幅優先探索 』の解法がわかる
  • 記事の作者のアルゴリズム問題全般へのアプローチがわかる

今回の問題

ATC 001 A 幅優先探索 → 問題文はこちら

記事の作者の回答のコード

from collections import deque

# ==============================================================
# return: スタートのマスを代入すると、スタートからゴールまでの最短手数を出力
# pre, post: 問題文に記載 -> 2 3 のマスの解釈を 3行目の2列目にあるマス というのではなく、2次元配列の2行目の3行目にあるマス と最初考えた方が混乱しないかも。

# ==============================================================
# ★ step1 問題文を解くために必要な迷路をインプットする
# ★ step2 幅優先探索でスタートからゴールにむかい上下左右に探索をさせる。
# ★ step3 探索を進む際に、これから進むマス = 前回進んだマスのスタートからの手数 + 1 をし、マーキングをする。
# ★ step4 ゴールにたどり着いた際、ゴールのマス時点でのスタートからの手数を返す


#問題分の行と列の数をインプット
r, c = map(int, input().split())
#スタートのマスの場所をインプット
sx, sy = map(int, input().split())
#ゴールのマスの場所をインプット
gx, gy = map(int, input().split())
sy -= 1
sx -= 1
gx -= 1
gy -= 1
#r個分ある迷路の描画を一列ずつインプット
maze = [list(input()) for i in range(r)]


#幅優先探索
def bfs():
    # 上下左右の4方向に分岐させる (今回は1行目の0行目みたいな解釈になるので、どの方向かは厳格に考えない方が無難?)
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]

    #探索をする際にスタートからの手数を記憶するために、別で新たに迷路と同じ大きさのモノを用意。
    d = [[float("inf")] * c for i in range(r)]
    #キューの作成
    que = deque([])
    #スタートのマスをいれる
    que.append((sx, sy))
    #スタートを0とする(今後マスを進めるたびに加算していく。)
    d[sx][sy] = 0
    
    while que:
        #先入先出しで四方向に順番に検索していく
        p = que.popleft() 
        #popしたものがゴールか判断
        if p[0] == gx and p[1] == gy:
            break
        #四方向の指定
        for i in range(4):
            #四方向にすすむ     
            nx = p[0] + dx[i]
            ny = p[1] + dy[i]
            #指定いる座標が迷路内か判定
            if 0 <= nx < r and 0 <= ny < c :
                #指定した座標が塀ではないか判定
                if maze[nx][ny] != "#" :
                    #指定した座標が未開拓であることを判定
                    if d[nx][ny] == float("inf"):
                        que.append((nx, ny))
                        #新しく開拓する場所に、既に開拓した場所の値を+1し代入させる
                        d[nx][ny] = d[p[0]][p[1]] + 1
    #popした際の進んだ値を返す
    return d[gx][gy]

print(bfs())

回答の解説

記事の作者が思う今回のアルゴリズム問題の回答ポイント

  • 迷路やスタート及びゴールを入力する際、迷路が配列で扱う関係で0番目スタートであることを意識
  • 幅優先探索であるため、先入先出しのためのpopleftメソッドを使う
  • 条件分岐として、迷路の範囲内か、塀か、未探索かを判断する
  • 探索先に前回探索した時のスタートからの手数+1をする

#このコードの課題感

  • 今回の前提として〜行目の〜行目のマスとしたが、仮に「2行2列目」がスタートであると解釈する場合、今回の変数x(列),y(行)がちょっと気持ちが悪くなる
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?