This article blog link:http://blog.csdn.net/jdh99 , author: jdh, reprint please specify.
surroundings:
Host: WIN10
Python version: 3.5
Development environment: pyCharm
Algorithm flow analysis:
data structure:
- frontier: the edge. Store unexpanded nodes
- explored : Explore the set. The state is stored (note that the previous algorithm is different)
Process:
- If the edge is empty, it returns failure. Operation: EMPTY? (frontier)
- Otherwise, select a leaf node from the edge. Operation: POP(frontier)
- Put the state of the leaf node in the exploration set
- Traverse all actions of leaf nodes
- Each action generates child nodes
- If the state of the child node is not in the exploration set or edge, then the target test: pass back
- If it fails, put it on the edge. Operation: INSERT( child , frontier)
Note: The algorithm only puts the state of the leaf node into the exploration set before traversing all the actions of the leaf node, that is, before the width search. In the traversal process, if the child node fails the target test, the state of the child node is not put into the exploration set, but the child node is placed on the edge, and the next round of traversal based on the width of the child node is prepared.
Algorithm performance analysis:
- complete
- Not optimal
- time complexity:
Assuming that each state has b successors and the depth of the solution is d, the total number of nodes:
b + b^2 + b^3 + … + b^d = O(b^d)
The above algorithm performs target detection when the node is expanded instead of when it is generated, so the time complexity should be O(b^(d+1))
- Space complexity:
每个已扩展的节点都保存到探索集,探索集的节点数: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
child node:state:Fagaras path cost:743
child node:state:Pitesti path cost:633
child node:state:Giurgiu path cost:622
add child to child
child node:state:Urziceni path cost:617
this child is goal!
from city: Zerind to city Urziceni search success
Zerind->Oradea->Sibiu->Fagaras->Bucharest->Urziceni
bibliography: