刚刚开始学习CS50人工智能入门课程,我认为我已经正确实现了BFS队列搜索算法来寻找两个演员之间的最短路径。我不知道可能的问题出在哪里,但我希望有人能指出我可能做错的地方。此外,没有任何错误提示,这实际上让问题变得更加难以理解。
def shortest_path(source, target):
"""
返回从源到目标的最短路径列表,包含(movie_id, person_id)对。
如果没有可能的路径,则返回None。
"""
# 初始化前沿为队列,因为BFS使用队列并能找到最短路径
frontier = QueueFrontier()
# 将第一个节点添加到前沿
frontier.add(Node(source, None, None))
# 初始化已探索节点为一个空集合
nodesExplored = set()
if source == target:
raise Exception("不能选择同一个演员两次!")
# 持续循环直到找到解决方案
while True:
# 如果没有解决方案,则返回None
if frontier.empty():
return None
# 从前沿选择一个节点并移除它
node = frontier.remove()
# 如果节点是目标节点,则我们已经达到目标状态,即我们的解决方案
if node.state == target:
# 初始化解决方案数组
solutions = []
# 如果节点有父节点,则继续搜索
while node.parent is not None:
solutions.append(node.action, node.state)
node = node.parent
solutions.reverse()
return solutions
# 标记节点为已探索
nodesExplored.add(node.state)
# 将邻居节点添加到前沿
for movie_id, person_id in neighbors_for_person(node.state):
if not frontier.contains_state(person_id) and person_id not in nodesExplored:
child = Node(person_id, node, movie_id)
frontier.add(child)
应该发生的情况是:
$ python degrees.py large Loading data... Data loaded. Name: Emma Watson Name: Jennifer Lawrence 3 degrees of separation. 1: Emma Watson and Brendan Gleeson starred in Harry Potter and the Order of the Phoenix 2: Brendan Gleeson and Michael Fassbender starred in Trespass Against Us 3: Michael Fassbender and Jennifer Lawrence starred in X-Men: First Class
但是在我输入第二个演员后什么都没有发生。屏幕保持空白,没有返回任何东西,甚至没有错误提示,所以我得到的是:
$ python degrees.py large Loading data... Data loaded. Name: Emma Watson Name: Jennifer Lawrence
回答:
我的猜测是你的frontier.contains_state(person_id)
检查过多,因为你阻止了将同一演员在不同电影中的节点添加到前沿,从而切断了可能的解决方案路径
这个似乎可以工作:
def shortest_path(source, target):
frontier = QueueFrontier()
frontier.add(Node(source, None, None))
nodesExplored = set()
if source == target:
raise Exception("不能选择同一个演员两次!")
while True:
if frontier.empty():
return None
node = frontier.remove()
if node.state == target:
solutions = []
while node.parent is not None:
solutions.append((node.action, node.state))
node = node.parent
solutions.reverse()
return solutions
nodesExplored.add(node.state)
for movie_id, person_id in neighbors_for_person(node.state):
if not (person_id in nodesExplored):
child = Node(person_id, node, movie_id)
frontier.add(child)
然而,课程笔记也提到:“如果你检测到目标节点,无需将其添加到前沿,你可以直接返回解决方案。”我认为你的代码可以通过移动目标检查来进一步改进…祝你在课程中好运,我也刚开始学习cs50 😉