Uninformed search Python实现【译】

本文介绍了盲目搜索算法的基础概念,包括深度优先搜索(DFS)、广度优先搜索(BFS)及一致代价搜索(UCS),并提供了Python实现示例。通过对比不同算法的特点,帮助读者理解它们的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

译自 Uninformed search algorithms in Python
版权所有,如需转载,请联系译者

图的搜索可以分为uninformed搜索和informed搜索,两者的区别是前者是的搜索是盲目的,它不知道目标节点在哪,而后者是启发式的搜索。

主要的uninformed 搜索分为以下三类:

  • 深度优先搜索(DFS)

  • 广度优先搜索(BFS)

  • 一致代价搜索(UCS)

创建图

使用邻接矩阵的形式创建图,为简便起见,这里省去节点的其他信息,直接使用一个字典表示,key表示节点,value表示邻接节点:

small_graph = {
    'A': ['B', 'C'],
    'B': ['D', 'A'],
    'C': ['A'],
    'D': ['B']
}

深度优先搜索

深度优先搜索会优先检索第一个邻接节点,然后重复这个过程,直到到达分支的底部,然后回溯。DFS可以通过递归实现,也可以通过递归实现。

具体实现需要保存已经访问的节点,同时判断边缘条件:

def dfs(graph, start, goal):
    visited = set()
    stack = [start]

    while stack:
        node = stack.pop()
        if node not in visited:
            visited.add(node)

            if node == goal:
                return
            for neighbor in graph[node]:
                if neighbor not in visited:
                    stack.append(neighbor)

广度优先搜索

实际上,只需要将上面算法中的stack改为queue,即可实现广度优先搜索。深度优先搜索总是会展开最新的节点,而广度优先搜索总是展开最老的节点,这就是他们为什么一个使用栈,一个使用队列的原因。

from collections import deque

def bfs(graph, start, goal):
    visited = set()
    queue = [start]

    while queue:
        node = queue.pop()
        if node not in visited:
            visited.add(node)

            if node == goal:
                return
            for neighbor in graph[node]:
                if neighbor not in visited:
                    queue.appendleft(neighbor)

一致代价搜索

该算法主要针对的是加权图,加权图每条边都有一个权值,权值低的边优先遍历,首先,我们创建一个加权图类:

class Graph:
    def __init__(self):
        self.edges = {}
        self.weights = {}

    def neighbors(self, node):
        return self.edges[node]

    def get_cost(self, from_node, to_node):
        return self.weights[(from_node + to_node)]

UCS跟广度优先搜索类似,也使用一个queue实现,但是使用的是加权队列

from queue import PriorityQueue

当每条边的cost相同时,UCS实际上就是BFS。

def ucs(graph, start, goal):
    visited = set()
    queue = PriorityQueue()
    queue.put((0, start))

    while queue:
        cost, node = queue.get()
        if node not in visited:
            visited.add(node)

            if node == goal:
                return
            for i in graph.neighbors(node):
                if i not in visited:
                    total_cost = cost + graph.get_cost(node, i)
                    queue.put((total_cost, i))

总结

UCS会检索一条权重之和最小的路径,而BFS会检索出一条边最少的路径。

《人工智能导论》作业2 对应教学内容:Lecture2:Solving Problems by Uninformed Searching 题目:(参考AIMA(3rd edition)习题3.9)传教士野人问题求解 三个传教士和三个野人在河的一边,有一条能1载一个人或两个人的船。请设法使所有人都渡到河的另一边。为了防止野人攻击传教士,无论在河的哪一边,都不能让野人人数超过传教士人数,否则野人就会攻击传教士。假设传教士和野人都会划船,请为传教士和野人规划一个安全的过河方案。这个问题在AI领域很有名,它是第一个从分析的观点探讨问题形式化的论文的主题(Amarel,1968)。 作业要求: 1.将传教士野人问题形式化表述为一个搜索问题。明确定义状态表示、初始状态、目标状态、可行的动作集合、状态转移函数、动作代价,并分析该问题的状态空间。 2.针对该问题,设计并实现广度优先搜索(BFS)算法(建议用Python): a)采用队列存储等待扩展的节点; b)用一个集合存储已访问过的状态,避免重复访问; c)当搜索到目标状态时,输出从初始状态到目标状态的状态转移序列,统计搜索空间中被访问过的状态总数; d)若搜索完整个状态空间也未找到解,则输出"No solution"。 3.针对该问题,设计并实现深度优先搜索(DFS)算法(建议用Python): a)采用栈存储等待扩展的节点; b)用一个集合存储已访问过的状态; c)搜索过程中,选择第一个遇到的可行动作进行扩展,直到达到目标状态,或遍历所有状态; d)当搜索到目标状态时,输出从初始状态到目标状态的状态转移序列,统计搜索空间中被访问过的状态总数; e)若搜索完整个状态空间也未找到解,则输出"No solution"。 4.分析BFS和DFS在该问题上的时间、空间复杂度,并比较它们搜索过程中扩展节点数量的差异。你认为哪种算法更适合求解该问题? 5.讨论采用无信息搜索算法求解该问题可能存在的limitation。你有什么优化搜索效率的思路吗? 评分标准: 1.问题形式化表示是否准确、完整(20分); 2.BFS、DFS算法设计实现的正确性、规范性、注释是否充分等(30分); 3.复杂度分析是否合理,算法比较是否有理有据,对无信息搜索局限性的认识和改进思路(30分); 4.报告的清晰度、逻辑性和表达能力,算法运行情况,提交材料的完整性和规范性(20分)。 提交方式: 以压缩包形式(命名:班级+学号+姓名+A2)提交如下文件: 1.问题形式化表述、算法设计(伪代码)、算法分析、比较和讨论的文档(PDF或word格式); 2.实现BFS和DFS的源代码。
最新发布
06-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值