地图lines_从广度优先深度优先到地图搜索算法

问题描述:

用搜索算法模拟解决地铁换乘问题!

例如:

输入:search('徐家汇', '人民广场')

输出: 徐家汇->A->B-C->人民广场

import random
import networkx as nx
from collections import  defaultdict
import matplotlib.pyplot as plt

为了简化,这里不使用真实的地铁数据,而采用简单的随机生成的数据来进行模拟

station = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
station = [i for i in station]
#station
def generate_lines(station, num=4):
    lines = []
    step = len(station)//num
    start,end = 0,step
    cross_staions = station[-7:]
    station = station[:-7]
    step = len(station)//num
    for i in range(num):
        lines.append(station[start:end])
        new_step = step + random.randint(-1,1)
        start = end 
        end += new_step
        if i==num-1:
            end = len(station)
    for line in lines:
        insert_point = random.sample(cross_staions, random.randint(2,4))
        for p in insert_point:
            line.insert(random.randint(1,len(line)-2), p)
    return lines
lines = generate_lines(station)

绘制一下生成随机地铁路线

G = nx.Graph()
colors = ['r','b','g','k','y']
for index,line in enumerate(lines):
    for i in range(len(line)-1):  
        G.add_edge(line[i],line[i+1],color=colors[index])
# pos = nx.circular_layout(G)
pos = nx.fruchterman_reingold_layout(G)
edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]
plt.figure(figsize=(10,5))
nx.draw(G,pos=pos,edges=edges, edge_color=colors, width=2,node_size=30,with_labels=True)

bcf335e4a86a691afb96aad56841c3dd.png

生成图信息,即无向图的连接信息(每个节点连接的节点是什么)

graph_info = defaultdict(list)
for line in lines:
    for i,value in enumerate(line):
        if i<len(line)-1:
            graph_info[value].append(line[i+1])
        if i>0:
            graph_info[value].append(line[i-1])

标准的广度优先和深度优先遍历算法

def bdfs(graph, start):
    visited = [start]
    seen = set()
    path = []
    while visited:
        froninter = visited.pop(0) # 模拟队列
        if froninter in seen: continue  #如果元素已经被访问则跳过本次
        for successor in graph[froninter]: #遍历所有连接点
            if successor in seen: continue  #如果当前元素连接点被访问则跳过本次
#             visited = visited + [successor] # 每次访问旧点(和之前pop(0)对应) -> breath first
            visited = [successor] + visited # 每次访问新点 -> depth first
            # 所以说,这个扩展顺序其实是决定了我们的深度优先还是广度优先
        seen.add(froninter)
        path.append((froninter))
    return path
a = bdfs(graph_info,"F")

以上可以验证一下深度优先和广度优先算法的正确性!

算法改进

从标准的广度优先算法改进成可以搜索A->B路径的算法,我们对每次访问的节点进行判断是否到达了目标点,如果到达则搜索完毕,返回路径

def search(start, destination, connection_grpah, sort_candidate, by_the_way =[]):
    #默认是深度优先的话容易一条路走到黑,
    pathes = [[start]]  #每走一步都添加一个新的路径  
    visitied = set()
    
    while pathes:
        path = pathes.pop(0)   #获取当前要访问的路径, 控制深度 广度path = pathes.pop()则变成深度优先 
        froninter = path[-1]   #获取当前达到的节点
        if froninter in visitied: continue
        for city in connection_grpah[froninter]:
            if city in path: continue  # eliminate loop 防止环形,也防止重复访问,和city in visitied有同样效果          
            new_path = path + [city]
            pathes.append(new_path)
            if city == destination: return new_path
        visitied.add(froninter)
        
        ##对每次新的路径进行排序
        pathes = sort_candidate(pathes, by_the_way)
def transfer_stations_first(pathes,*arg): 
    ##总站数最少策略
    return sorted(pathes, key=len)
def transfer_as_much_possible(pathes,*arg):
    ##总站数最多策略
    return sorted(pathes, key=len, reverse=True)
def pretty_print(station):
    print(len(station))
    print(' ->'.join(station))

pretty_print(search('F', 'P', graph_info, sort_candidate=transfer_stations_first))
5
F ->E ->V ->X ->P

完成,可以达到预期效果

总结

该算法还有许多可以改进的地方

  1. 如果要添加中途点,那么搜索算法如何改进?
  2. 如果假如站与站之间的位置信息(两站时间消耗),搜索算法如何修改?
  3. 如果想最少换乘,搜索算法如何改进?

进一步改进会越来越接近地图里面的效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值