广度优先搜索–寻找供货商
广度优先搜索索(breadth-first search,BFS)是一种用于图的查找算法,可帮助回答两类问题
- 问题描述
假设你经营着一个芒果农场,需要寻找芒果销售商,以便将芒果卖给他。为此,你可在朋友中查找。假设你没有朋友是芒果销售商,那么你就必须在朋友的朋友中查找。你的目标是在你的人际关系网中找到一位芒果销售商。
- 代码
# 构建图
graph = {}
graph['you'] = ['Alice', 'Bob', 'Claire']
graph['Bob'] = ['Anuj', 'Peggy']
graph['Alice'] = ['Peggy']
graph['Claire'] = ['Thom', 'Jonny']
graph['Peggy'] = []
graph['Thom'] = []
graph['Jonny'] = []
graph['Anuj'] = []
# 广度优先搜索
def bfs(name):
# 售货商是Jonny
def person_is_seller(name):
if name == 'Jonny':
return True
else:
return False
# 使用队列存储待查找的人
from collections import deque
search_queue = deque()
search_queue.append(name)
processed = [] # 存储已经查找过的人,避免多次查找或无限循环
while search_queue:
name = search_queue.popleft() # 出队
if name not in processed and person_is_seller(name):
print('找到售货商嘞,就是 {} !'.format(name))
return
else:
processed.append(name)
search_queue += graph[name] # 入队
print('你的朋友网里妹有供货商啊...')
bfs('you')
# 找到售货商嘞,就是 Jonny !
- 运行时间
贪心算法–集合覆盖问题
- 问题描述
假设你办了个广播节目,要让全美8个州的听众都收听得到。为此,你需要决定在哪些广播台播出。在每个广播台播出都需要支付费用,因此你力图在尽可能少的广播台播出。现有广播台名单如下。
每个广播台都覆盖特定的区域,不同广播台的覆盖区域可能重叠。
- 目标
- 找出覆盖8个州的最小广播台集合
- 解决方案
- 分析
- 只要还有未覆盖地区,就进行一轮筛选:
在未选取的广播站中找到覆盖未覆盖地区最多的广播站,将其选中后,从未覆盖地区中剔除该广播站覆盖的区域 - 不断进行上述过程,直到覆盖全部地区
- 只要还有未覆盖地区,就进行一轮筛选:
- 代码
states_needed = {"mt", "wa", "or", "id", "nv", "ut", "ca", "az"}
# 键为广播站名称,值为广播站覆盖的地区名称‘集合’
stations = {}
stations["kone"] = {"id", "nv", "ut"}
stations["ktwo"] = {"wa", "id", "mt"}
stations["kthree"] = {"or", "nv", "ca"}
stations["kfour"] = {"nv", "ut"}
stations["kfive"] = {"ca", "az"}
def search(stations, states_needed):
ans = []
while states_needed:
max_cover_nums = 0
max_station = None
for station, state in stations.items():
union = states_needed & state
if len(union) > max_cover_nums:
max_cover_nums = len(union)
max_station = station
ans.append(max_station)
states_needed -= stations[max_station]
del stations[max_station]
return ans
print(search(stations, states_needed))
迪杰斯特拉算法–加权有向无环图的最短路径
- 求解加权图的最短路径
- 只适用于有向无环图(directed acyclic graph,DAG)
- 广度优先搜索与迪杰斯特拉算法的区别
+ 要计算非加权图中的最短路径,可使用广度优先搜索。
+ 要计算加权图中的最短路径,可使用狄克斯特拉算法。
- 问题描述
- 有以下加权有向无环图,其中每个数字表示的都是时间,单位分钟。需要找出从起点到终点耗时最短的路径
- 算法步骤
- 找出最便宜的节点,即可在最短时间内前往的节点。
- 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销。
- 重复这个过程,直到对图中的每个节点都这样做了。
- 计算最终路径。
- 实现
# 构建加权有向无环图
graph = {}
graph['start'] = {'A': 6, 'B': 2}
graph['A'] = {'end': 1}
graph['B'] = {'A': 3, 'end': 5}
graph['end'] = None
# 记录每一个接电的前驱结点
parents = {}
parents['start'] = None
parents['A'] = 'start'
parents['B'] = 'start'
parents['end'] = None
# 记录每一个结点的最短距离
costs = {}
costs['A'] = 6
costs['B'] = 2
costs['end'] = float('inf')
def findLowestPath(graph, parents, costs):
processed = ['end']
# 寻找当前未处理过的距离最近的点
def findLowestCostNode():
lowest_cost = float('inf')
lowest_cost_node = None
for node in costs:
c = costs[node]
if node not in processed and c < lowest_cost:
lowest_cost = c
lowest_cost_node = node
return lowest_cost_node
node = findLowestCostNode()
while node:
c = costs[node]
for k, v in graph[node].items():
if c + v < costs[k]:
costs[k] = c + v
parents[k] = node
processed.append(node)
node = findLowestCostNode()
# 调用
findLowestPath(graph, parents, costs)
# 输出
for node in costs:
print('到达{:3}的最短距离为{:2}'.format(node, costs[node]), end=',')
path = node
while parents[node]:
path = parents[node]+'-->'+path
node = parents[node]
print(path)
# 到达A 的最短距离为 5,start-->B-->A
# 到达B 的最短距离为 2,start-->B
# 到达end的最短距离为 6,start-->B-->A-->end
参考资料: