LoginSignup
1
8

More than 5 years have passed since last update.

[Algorithm入門]最短経路を探す[Python3]

Last updated at Posted at 2017-03-15

テーマ

地形コストを情報として持つマップにおいて、スタート地点とゴール地点までを最低コストで結ぶルートを探す。(例えば、SRPG系のゲームでは、平地、家屋、森、山へ移動するときに地形コストが考慮されている)

アルゴリズム

1) 座標と地形コストが対応した配列を用意(cost_map)
2) ゴール地点を始点として、各地点まで移動にかかるコストを求め、配列を作成(rout_cost)
3) 各地点の移動コスト(rout_cost)をもとに、スタート地点からコストの小さい点をたどる

注) 補足(プログラムを書く上で用いるテクニック)
再帰関数を用います。

実践

1) 例えば以下のような地形コストを持つマップにおいてスタート ( x3, y0 ) からゴール ( x1, y6 ) への最短経路を考える。

y0 y1 y2 y3 y4 y5 y6
x0 4 3 1 1 1 2 3
x1 3 2 1 2 1 1 1
x2 2 1 3 3 2 3 2
x3 2 3 5 3 2 4 3

地形コストを要素に持つ配列cost_map、さらに無限値を要素に持つ配列rout_costを用意する。

alg_01.py
s = [3,0]; g = [1,6]  ## start and goal position
cost_map = [[4,3,1,1,1,2,3],\
            [3,2,1,2,1,1,1],\
            [2,1,3,3,2,3,2],\
            [2,3,5,3,2,4,3]]
m = len(cost_map)
n = len(cost_map[0])
rout_cost = [[float("inf") for j in range(n)] for i in range(m)]

2) ゴール地点を始点として各地点までの移動コストを計算し、計算結果に基づいて上で用意したrout_costを更新する。

alg_02.py
def calc_rout_cost(x,y,cost_tmp):
    cost_tmp += cost_map[x][y]
    if cost_tmp < rout_cost[x][y]:
        rout_cost[x][y] = cost_tmp
        if y < n-1:
            calc_rout_cost(x,y+1,cost_tmp)
        if y > 0:
            calc_rout_cost(x,y-1,cost_tmp)
        if x < m-1:
            calc_rout_cost(x+1,y,cost_tmp)
        if x > 0:
            calc_rout_cost(x-1,y,cost_tmp)
calc_rout_cost(g[0],g[1],-cost_map[g[0]][g[1]])

出来上がったrout_costは以下の通り。ゴール地点(x6,y1)はゼロになることに注意。

x0 x1 x2 x3 x4 x5 x6
y0 12 8 5 4 3 3 3
y1 10 7 5 4 2 1 0
y2 10 8 8 7 4 4 2
y3 12 11 13 9 6 8 5

3) 最後に、スタートからゴールまでの最短経路を探す。

alg_03.py
def search_rout(x,y):
    tmp = rout_cost[x][y]
    tmp_x, tmp_y = x, y
    if x > 0 and rout_cost[x-1][y] < tmp :
        tmp_x, tmp_y = x-1, y
        tmp = rout_cost[tmp_x][tmp_y]
    if x < m-1 and rout_cost[x+1][y] < tmp :
        tmp_x, tmp_y = x+1, y
        tmp = rout_cost[tmp_x][tmp_y]
    if y > 0 and rout_cost[x][y-1] < tmp :
        tmp_x, tmp_y = x, y-1
        tmp = rout_cost[tmp_x][tmp_y]
    if y < n-1 and rout_cost[x][y+1] < tmp :
        tmp_x, tmp_y = x, y+1
        tmp = rout_cost[tmp_x][tmp_y]
    if rout_cost[x][y] == 0: return;
    rout_list.append([tmp_x,tmp_y])
    search_rout(tmp_x,tmp_y)

rout_list = []
rout_list.append(s)
search_rout(s[0],s[1])

最短経路は

result.py
print(rout_list)
## [[3, 0], [2, 0], [2, 1], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]]

となる。

参考文献

柳井政和「プログラマのためのコードパズル」技術評論社 (2014)
詳しい説明は文献をあたってください。Javascriptで記述してあります。

1
8
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
1
8