报告错误
如果你发现该网页中存在错误/显示异常,可以从以下两种方式向我们报告错误,我们会尽快修复:
- 使用 CS Club 网站错误 为主题,附上错误截图或描述及网址后发送邮件到 286988023@qq.com
- 在我们的网站代码仓库中创建一个 issue 并在 issue 中描述问题 点击链接前往Github仓库
你使用哪种语言?我们会根据你选择的语言显示对应的代码示例
前置条件
-
理论基础:时间复杂度 Time Complexity -
数据结构:队列 Queue -
数据结构:优先队列 Priority Queue -
理论知识:图的表达 How to Represent a Graph -
算法:广度优先算法 Breadth First Search -
算法:深度优先算法 Depth First Search
代价统一搜索策略
在之前的深度优先搜索和广度优先搜索中,我们一般都只考虑目标节点与出发节点之间的图上距离1而非真实距离2 - 这在一些简单的场景下没有什么问题,但是在一些情况下图上的距离与真实距离并不一致。例如下图:
在下面这张图中, $G$ 与 $S$ 之间的图上距离最小路径应该是直线 $A$。但是,如果我们要看 $G$ 和 $S$ 之间的路径权重之和最小的话我们会发现最优路径并不是 $A$ 而是 $A*$,因为 $A$ 的路径权重之和为 $10 + 5 = 15$ 而 $A*$ 的路径权重之和为 $1 + 2 + 1 + 1 = 5$。
为了找到实际距离最短的路径而不是图上距离最短的路径,人们在 BFS 的基础上做出了改动,产生了更加准确的 UCS 代价统一搜索策略。在 BFS 中,Queue
的性质距离初始节点图上距离最小的节点会优先被展开,而在 UCS 中,我们用 Priority Queue
实现 Fringe,这个优先队列对待探索节点的排序是基于初始节点到待探索节点的实际距离决定的。
一张图的 “等 Cost 线“
在 UCS 对图像进行遍历的过程中,如果在 Fringe 中 Actual Cost 最小的节点的 Actual Cost 为 $C$,则所有已探索的节点的 Actual Cost 都一定$\leq C$。通过这个性质,我们可以轻易证明UCS找到的第一个目标节点一定是距离初始节点实际距离最小的目标节点(即最优解)。
代价统一算法的实现
import heapq # The Python Module for Priority Queue def uniformCostSearch(initialState, getSuccessor, getValidActions, getActionCost): """ :param initialState: The Initial State of problem (sometimes the 'current state') :param getSuccessor: The State Transition Function that return the successors given the current state and action :param getValidActions: A function that takes current state and return a list of valid actions under current state :param getActionCost: A function that will return cost of action given action and current state """ fringe = [] # The only difference between BFS and DFS exploredStates = set() # Add the Initial State into the Fringe before Searching Actually Start. # Instead of storing state directly in the fringe, we will use a tuple to store state, where the # 0th param of tuple is cumulative cost # 1th param of tuple is the state heapq.heappush(fringe, (0, initialState)) # The initial cost is 0 while len(fringe) > 0: cost, currState = heapq.heappop(fringe) if currState in exploredStates: continue else: exploredState.add(currState) # Do Something Here for action in getValidActions(currState): # Add Successor States into the fringe successor = getSuccessor(currState, action) if successor not in exploredStates: deltaCost = getActionCost(currrState, action) heapq.heappush((cost + deltaCost, successor))
Not Implemented Yet, see Python Version
练习
暂无练习 (一般与其他算法搭配使用,很少有单独的练习出现,思考一下之前做过的一些 BFS / DFS 题目有没有可能用 UCS 取代原来的算法来优化?)