「人材獲得作戦・4 試験問題ほか」を解いてみた(1)

人材獲得作戦・4 試験問題ほか」を解いてみた。

問題
壁とスペースで構成された迷路が与えられたとき、スタート地点からゴール地点に至る最短経路を求めよ

**************************
*S* *                    *
* * *  *  *************  *
* *   *    ************  *
*    *                   *
************** ***********
*                        *
** ***********************
*      *              G  *
*  *      *********** *  *
*    *        ******* *  *
*       *                *
**************************

最初に思いついた方法はスタート地点から各地点への距離を求めて、ゴール地点から最短距離をたどるという方法です。

import sys, copy

def main():
    # 地図の読み込み
    map = load_map()
    # スタート地点とゴール地点の座標を取得する
    start = parse_pos(map, "S")
    goal = parse_pos(map, "G")
    # スタート地点から各座標への距離を求める
    distance_map = measure_distance(copy.deepcopy(map), [start], 1)
    # ゴール地点から最短距離をたどってスタート地点に行く
    route = examine_route(distance_map, goal, [])
    # 答えを出力する
    print_answer(map, route)

まず最初に問題を解くのに必要な情報を取得します。

def load_map():
    """地図を読み込む"""
    map = []
    for line in sys.stdin:
        map.append(list(line.strip()))
    return map

def parse_pos(map, p):
    """スタート地点の座標を取得する"""
    for y in range(len(map)):
        for x in range(len(map[y])):
            if map[y][x] == p: return (y, x)
    raise Exception, '%s is not found.' % p

スタート地点から一マスずつ距離を地図に記載していきます。

def measure_distance(map, pos_list, dist):
    """
    スタート地点から各座標への距離を求める
    map 地図
    pos_list 探索開始地点
    dist 距離
    """
    next_pos_list = []
    for y,x in pos_list:
        for pos_y,pos_x in [(y,x+1),(y,x-1),(y+1,x),(y-1,x)]:
            if map[pos_y][pos_x] == ' ':
                map[pos_y][pos_x] = dist
                next_pos_list.append((pos_y,pos_x))
    if len(next_pos_list) == 0: return map
    return measure_distance(map, next_pos_list, dist+1)

次のような地図ができました。

 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 *  S  *  8  * 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29  *
 *  1  *  7  *  9 10  * 14 15  *  *  *  *  *  *  *  *  *  *  *  *  * 29 30  *
 *  2  *  6  7  8  * 16 15 16 17  *  *  *  *  *  *  *  *  *  *  *  * 30 31  *
 *  3  4  5  6  * 18 17 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32  *
 *  *  *  *  *  *  *  *  *  *  *  *  *  * 23  *  *  *  *  *  *  *  *  *  *  *
 * 37 36 35 34 33 32 31 30 29 28 27 26 25 24 25 26 27 28 29 30 31 32 33 34  *
 *  * 37  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 * 39 38 39 40 41 42  * 46 47 48 49 50 51 52 53 54 55 56 57 58 59  G 65 66  *
 * 40 39  * 41 42 43 44 45 46  *  *  *  *  *  *  *  *  *  *  * 60  * 64 65  *
 * 41 40 41 42  * 44 45 46 47 48 49 50 51  *  *  *  *  *  *  * 61  * 63 64  *
 * 42 41 42 43 44 45 46  * 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63  *
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *

次にゴール地点Gから上下左右の座標を調べて、もっとも距離の小さい座標を見つけます。
見つかったらその座標を記録して、次にその座標からもっとも距離の小さい座標を見つけます。
以下、スタート地点が見つかるまで繰り返します。
スタート地点が見つかったら、今までたどってきた座標を返します。

def examine_route(map, goal, route):
    """
    ゴール地点から最短距離をたどってスタート地点に行く
    distance_map スタート地点からの距離を記載した地図
    goal 検索開始地点の座標
    """
    y,x = goal
    next_pos = None
    dist = len(map) * len(map[0])
    for pos_y,pos_x in [(y,x+1),(y,x-1),(y+1,x),(y-1,x)]:
        cell = map[pos_y][pos_x]
        if cell == 'S': return route
        elif cell == "*": continue
        elif cell < dist:
            dist = cell
            next_pos = (pos_y, pos_x)
    route.append(next_pos)
    return examine_route(map, next_pos, route)

最短経路が見つかったので、出力します。

def print_answer(map, route):
    """答えを出力する"""
    for y in range(len(map)):
        for x in range(len(map[y])):
            if (y,x) in route:
                sys.stdout.write("$")
            else:
                sys.stdout.write(map[y][x])
        print

ソースコードの全体は次のようになります。

#python
# -*- coding: shift-jis -*-
import sys, copy

def main():
    # 地図の読み込み
    map = load_map()
    # スタート地点とゴール地点の座標を取得する
    start = parse_pos(map, "S")
    goal = parse_pos(map, "G")
    # スタート地点から各座標への距離を求める
    distance_map = measure_distance(copy.deepcopy(map), [start], 1)
    # ゴール地点から最短距離をたどってスタート地点に行く
    route = examine_route(distance_map, goal, [])
    # 答えを出力する
    print_answer(map, route)

def load_map():
    """地図を読み込む"""
    map = []
    for line in sys.stdin:
        map.append(list(line.strip()))
    return map

def parse_pos(map, p):
    """座標を取得する"""
    for y in range(len(map)):
        for x in range(len(map[y])):
            if map[y][x] == p: return (y, x)
    raise Exception, '%s is not found.' % p

def measure_distance(map, pos_list, dist):
    """
    スタート地点から各座標への距離を求める
    map 地図
    pos_list 探索開始地点
    dist 距離
    """
    next_pos_list = []
    for y,x in pos_list:
        for pos_y,pos_x in [(y,x+1),(y,x-1),(y+1,x),(y-1,x)]:
            if map[pos_y][pos_x] == ' ':
                map[pos_y][pos_x] = dist
                next_pos_list.append((pos_y,pos_x))
    if len(next_pos_list) == 0: return map
    return measure_distance(map, next_pos_list, dist+1)

def examine_route(map, goal, route):
    """
    ゴール地点から最短距離をたどってスタート地点に行く
    distance_map スタート地点からの距離を記載した地図
    goal 検索開始地点の座標
    """
    y,x = goal
    next_pos = None
    dist = len(map) * len(map[0])
    for pos_y,pos_x in [(y,x+1),(y,x-1),(y+1,x),(y-1,x)]:
        cell = map[pos_y][pos_x]
        if cell == 'S': return route
        elif cell == "*": continue
        elif cell < dist:
            dist = cell
            next_pos = (pos_y, pos_x)
    route.append(next_pos)
    assert next_pos != None
    return examine_route(map, next_pos, route)

def print_answer(map, route):
    """答えを出力する"""
    for y in range(len(map)):
        for x in range(len(map[y])):
            if (y,x) in route:
                sys.stdout.write("$")
            else:
                sys.stdout.write(map[y][x])
        print

if __name__ == "__main__":
    main()

コメント

  1. Pingback: 今更ながら『人材獲得作戦・4 試験問題』を解いてみた - Tools&Toolz

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください