人工知能学習:Pythonは幅優先探索アルゴリズムを実装します

人工知能学習:Pythonは幅優先探索アルゴリズムを実装します


この記事のブログリンク:http://blog.csdn.net/jdh99、作者:jdh、転載を明記してください。

 

周囲:

ホスト:WIN10

Pythonバージョン:3.5

開発環境:pyCharm


説明:
幅優先アルゴリズムを作成するには、「人工知能の最新の方法」を学びます。
本のアルゴリズムソースコード:



アルゴリズムフロー分析:

データ構造:

  • フロンティア:エッジ。拡張されていないノードを保存する
  • 探索:セットを探索します。状態が保存されます(前のアルゴリズムが異なることに注意してください)

処理する:

  • エッジが空の場合、失敗を返します。操作:空?(フロンティア)
  • それ以外の場合は、エッジからリーフノードを選択します。操作:POP(フロンティア)
  • リーフノードの状態を探索セットに入れます
  • リーフノードのすべてのアクションをトラバースします
    • 各アクションは子ノードを生成します
    • 子ノードの状態が探索セットまたはエッジにない場合、ターゲットテスト:パスバック
    • 失敗した場合は、端に置きます。操作:INSERT(、フロンティア)

 

注:アルゴリズムは、リーフノードのすべてのアクションをトラバースする前、つまり幅検索の前に、リーフノードの状態を探索セットに入れるだけです。トラバーサルプロセスでは、子ノードがターゲットテストに失敗した場合、子ノードの状態は探索セットに入れられませんが、子ノードはエッジに配置され、トラバーサルの次のラウンドは幅に基づいて行われます。子ノードが用意されています。

 

 

アルゴリズムのパフォーマンス分析:

  • コンプリート
  • 最適ではありません
  • 時間計算量:

各状態にb個の後続があり、解の深さがdであるとすると、ノードの総数は次のようになります。

b + b ^ 2 + b ^ 3 +…+ b ^ d = O(b ^ d)

上記のアルゴリズムは、ノードが生成されるときではなく展開されるときにターゲット検出を実行するため、時間計算量はO(b ^(d + 1))である必要があります。

  • スペースの複雑さ:

每个已扩展的节点都保存到探索集,探索集的节点数:O(b(d - 1)),边缘节点中:O(b^d)。所以控件复杂度为O(b^d),由边缘集所决定。

 




城市地图:




源码:

import pandas as pd
from pandas import Series, DataFrame

# 城市信息:city1 city2 path_cost
_city_info = None

# 按照路径消耗进行排序的FIFO,低路径消耗在前面
_frontier_priority = []


# 节点数据结构
class Node:
    def __init__(self, state, parent, action, path_cost):
        self.state = state
        self.parent = parent
        self.action = action
        self.path_cost = path_cost


def main():
    global _city_info
    import_city_info()

    while True:
        src_city = input('input src city\n')
        dst_city = input('input dst city\n')
        result = breadth_first_search(src_city, dst_city)
        if not result:
            print('from city: %s to city %s search failure' % (src_city, dst_city))
        else:
            print('from city: %s to city %s search success' % (src_city, dst_city))
            path = []
            while True:
                path.append(result.state)
                if result.parent is None:
                    break
                result = result.parent
            size = len(path)
            for i in range(size):
                if i < size - 1:
                    print('%s->' % path.pop(), end='')
                else:
                    print(path.pop())


def import_city_info():
    global _city_info
    data = [{'city1': 'Oradea', 'city2': 'Zerind', 'path_cost': 71},
            {'city1': 'Oradea', 'city2': 'Sibiu', 'path_cost': 151},
            {'city1': 'Zerind', 'city2': 'Arad', 'path_cost': 75},
            {'city1': 'Arad', 'city2': 'Sibiu', 'path_cost': 140},
            {'city1': 'Arad', 'city2': 'Timisoara', 'path_cost': 118},
            {'city1': 'Timisoara', 'city2': 'Lugoj', 'path_cost': 111},
            {'city1': 'Lugoj', 'city2': 'Mehadia', 'path_cost': 70},
            {'city1': 'Mehadia', 'city2': 'Drobeta', 'path_cost': 75},
            {'city1': 'Drobeta', 'city2': 'Craiova', 'path_cost': 120},
            {'city1': 'Sibiu', 'city2': 'Fagaras', 'path_cost': 99},
            {'city1': 'Sibiu', 'city2': 'Rimnicu Vilcea', 'path_cost': 80},
            {'city1': 'Rimnicu Vilcea', 'city2': 'Craiova', 'path_cost': 146},
            {'city1': 'Rimnicu Vilcea', 'city2': 'Pitesti', 'path_cost': 97},
            {'city1': 'Craiova', 'city2': 'Pitesti', 'path_cost': 138},
            {'city1': 'Fagaras', 'city2': 'Bucharest', 'path_cost': 211},
            {'city1': 'Pitesti', 'city2': 'Bucharest', 'path_cost': 101},
            {'city1': 'Bucharest', 'city2': 'Giurgiu', 'path_cost': 90},
            {'city1': 'Bucharest', 'city2': 'Urziceni', 'path_cost': 85},
            {'city1': 'Urziceni', 'city2': 'Vaslui', 'path_cost': 142},
            {'city1': 'Urziceni', 'city2': 'Hirsova', 'path_cost': 98},
            {'city1': 'Neamt', 'city2': 'Iasi', 'path_cost': 87},
            {'city1': 'Iasi', 'city2': 'Vaslui', 'path_cost': 92},
            {'city1': 'Hirsova', 'city2': 'Eforie', 'path_cost': 86}]

    _city_info = DataFrame(data, columns=['city1', 'city2', 'path_cost'])
    # print(_city_info)


def breadth_first_search(src_state, dst_state):
    global _city_info

    node = Node(src_state, None, None, 0)
    # 目标测试
    if node.state == dst_state:
        return node
    frontier = [node]
    explored = []

    while True:
        if len(frontier) == 0:
            return False
        node = frontier.pop(0)
        explored.append(node.state)
        if node.parent is not None:
            print('deal node:state:%s\tparent state:%s\tpath cost:%d' % (node.state, node.parent.state, node.path_cost))
        else:
            print('deal node:state:%s\tparent state:%s\tpath cost:%d' % (node.state, None, node.path_cost))

        # 遍历子节点
        for i in range(len(_city_info)):
            dst_city = ''
            if _city_info['city1'][i] == node.state:
                dst_city = _city_info['city2'][i]
            elif _city_info['city2'][i] == node.state:
                dst_city = _city_info['city1'][i]
            if dst_city == '':
                continue
            child = Node(dst_city, node, 'go', node.path_cost + _city_info['path_cost'][i])
            print('\tchild node:state:%s path cost:%d' % (child.state, child.path_cost))
            if child.state not in explored and not is_node_in_frontier(frontier, child):
                # 目标测试
                if child.state == dst_state:
                    print('\t\t this child is goal!')
                    return child
                frontier.append(child)
                print('\t\t add child to child')


def is_node_in_frontier(frontier, node):
    for x in frontier:
        if node.state == x.state:
            return True
    return False


if __name__ == '__main__':
    main()




 
     
 
     
利用算法求解:
input src city
Zerind
input dst city
Urziceni
deal node:state:Zerind parent state:None path cost:0
 child node:state:Oradea path cost:71
   add child to child
 child node:state:Arad path cost:75
   add child to child
deal node:state:Oradea parent state:Zerind path cost:71
 child node:state:Zerind path cost:142
 child node:state:Sibiu path cost:222
   add child to child
deal node:state:Arad parent state:Zerind path cost:75
 child node:state:Zerind path cost:150
 child node:state:Sibiu path cost:215
 child node:state:Timisoara path cost:193
   add child to child
deal node:state:Sibiu parent state:Oradea path cost:222
 child node:state:Oradea path cost:373
 child node:state:Arad path cost:362
 child node:state:Fagaras path cost:321
   add child to child
 child node:state:Rimnicu Vilcea path cost:302
   add child to child
deal node:state:Timisoara parent state:Arad path cost:193
 child node:state:Arad path cost:311
 child node:state:Lugoj path cost:304
   add child to child
deal node:state:Fagaras parent state:Sibiu path cost:321
 child node:state:Sibiu path cost:420
 child node:state:Bucharest path cost:532
   add child to child
deal node:state:Rimnicu Vilcea parent state:Sibiu path cost:302
 child node:state:Sibiu path cost:382
 child node:state:Craiova path cost:448
   add child to child
 child node:state:Pitesti path cost:399
   add child to child
deal node:state:Lugoj parent state:Timisoara path cost:304
 child node:state:Timisoara path cost:415
 child node:state:Mehadia path cost:374
   add child to child
deal node:state:Bucharest parent state:Fagaras path cost:532
 子ノード:状態:Fagarasパスコスト:743
 子ノード:状態:Pitestiパスコスト:633
 子ノード:状態:Giurgiuパスコスト:622
   子を子に追加
 子ノード:状態:Urziceniパスコスト:617
   この子が目標です!
都市から:ゼリンドから都市ウルジチェニへの検索成功
ゼリンド->オラデア->シビウ->ファガラス->ブカレスト->ウルジチェニ

ZerindからUrziceniへの最適なパスは、Zerind-> Arad-> Sibiu-> Rimnicu Vilcea-> Pitesti-> Bucharest-> Urziceniである必要があるため、このアルゴリズムは最適なアルゴリズムではなく、単なる解決策です。


参考文献:

1.「人工知能の現代的な方法」





おすすめ

転載: blog.csdn.net/jdh99/article/details/80851261