繁体   English   中英

如何从Python中的加权图计算路径的长度?

[英]How do I calculate the length of a path from a weighted graph in Python?

我正在做这个项目,但是在找出哪条路径的长度最短时遇到了问题。 设置是一家超市。 您从入口开始,然后在现金平台下车。 A,B,C,D点是超市中诸如烘烤等区域中的点。在“ via”输入中,您可以提供要通过的点。

#e = entrance
#k = cash desk
graph1 = {'e':{'a':1, 'b':5, 'c':6, 'd':6},
    'a':{'e':2, 'b':4, 'c':5, 'd':5, 'k':7},
    'b':{'e':5, 'a':5, 'c':3, 'd':5, 'k':6},
    'c':{'e':6, 'a':5, 'b':3, 'd':4, 'k':5},
    'd':{'e':6, 'a':3, 'b':5, 'c':4, 'k':2},
    'k':{'a':7, 'b':6, 'c':5, 'd':2}
}

start = input('start')
end = input('end')
required = input('via').split(',')

def find_all_paths(graph, start, end, path=[]):
  path = path + [start]
  if start == end:
      return [path]
  if not start in graph:
      return []
  paths = []
  for node in graph[start]:
      if node not in path:
          newpaths = find_all_paths(graph, node, end, path)
          for newpath in newpaths:
              paths.append(newpath)
  return paths

def exists_in_graph(graph, nodes):
  for node in nodes:
    if not node in graph:
      return False
  return True

allPaths = find_all_paths(graph1, start, end)
allPathsTroughNodes = list(filter(lambda x: exists_in_graph(x, required), 
allPaths))
print(allPathsTroughNodes)

输出:

start e
end k
via a,c,d
[['e', 'a', 'b', 'c', 'd', 'k'], ['e', 'a', 'b', 'd', 'c', 'k'], ['e', 'a', 
'c', 'b', 'd', 'k'], ['e', 'a', 'c', 'd', 'b', 'k'], ['e', 'a', 'c', 'd', 
'k'], ['e', 'a', 'd', 'b', 'c', 'k'], ['e', 'a', 'd', 'c', 'b', 'k'], ['e', 
'a', 'd', 'c', 'k'], ['e', 'b', 'a', 'c', 'd', 'k'], ['e', 'b', 'a', 'd', 
'c', 'k'], ['e', 'b', 'c', 'a', 'd', 'k'], ['e', 'b', 'c', 'd', 'a', 'k'], 
['e', 'b', 'd', 'a', 'c', 'k'], ['e', 'b', 'd', 'c', 'a', 'k'], ['e', 'c', 
'a', 'b', 'd', 'k'], ['e', 'c', 'a', 'd', 'b', 'k'], ['e', 'c', 'a', 'd', 
'k'], ['e', 'c', 'b', 'a', 'd', 'k'], ['e', 'c', 'b', 'd', 'a', 'k'], ['e', 
'c', 'd', 'a', 'b', 'k'], ['e', 'c', 'd', 'a', 'k'], ['e', 'c', 'd', 'b', 
'a', 'k'], ['e', 'd', 'a', 'b', 'c', 'k'], ['e', 'd', 'a', 'c', 'b', 'k'], 
['e', 'd', 'a', 'c', 'k'], ['e', 'd', 'b', 'a', 'c', 'k'], ['e', 'd', 'b', 
'c', 'a', 'k'], ['e', 'd', 'c', 'a', 'b', 'k'], ['e', 'd', 'c', 'a', 'k'], 
['e', 'd', 'c', 'b', 'a', 'k']]

但是我不知道如何计算每个找到的路径的长度以及如何从中找出最短的路径。

在构建路径时,您需要累积路径长度。 可以修改您现有的代码来做到这一点,但这很混乱。 一种更干净的方法是将函数转换为生成器,以便在找到它们时产生路径,而不是将其存储在路径列表中。

我们可以将生成器的输出传递给sorted函数,以获得按其长度排序的路径列表。

import sys

graph1 = {
    'e': {'a': 1, 'b': 5, 'c': 6, 'd': 6},
    'a': {'e': 2, 'b': 4, 'c': 5, 'd': 5, 'k': 7},
    'b': {'e': 5, 'a': 5, 'c': 3, 'd': 5, 'k': 6},
    'c': {'e': 6, 'a': 5, 'b': 3, 'd': 4, 'k': 5},
    'd': {'e': 6, 'a': 3, 'b': 5, 'c': 4, 'k': 2},
    'k': {'a': 7, 'b': 6, 'c': 5, 'd': 2}
}

#start = input('start ')
#end = input('end ')
#required = input('via ').split(',')
#if required == ['']:
    #required = []

# Hard-code some input data to make it easier to test the code
start, end = 'e', 'k'
required = []

def find_all_paths(graph, start, end, path=None, pathlen=0):
    if path is None:
        path = []
    path = path + [start]
    if start == end:
        yield pathlen, path
    if not start in graph:
        yield [], 0
        return

    for node, val in graph[start].items():
        if node not in path:
            yield from find_all_paths(graph, node, end, path, pathlen + val)

def exists_in_graph(graph, nodes):
    for node in nodes:
        if not node in graph:
            return False
    return True

if not exists_in_graph(graph1, [start, end] + required):
    print('Bad data!')
    sys.exit()

all_paths = sorted(find_all_paths(graph1, start, end))
for pathlen, path in all_paths:
    if exists_in_graph(path, required):
        print(path, pathlen)

产量

['e', 'a', 'd', 'k'] 8
['e', 'a', 'k'] 8
['e', 'd', 'k'] 8
['e', 'a', 'b', 'k'] 11
['e', 'a', 'c', 'k'] 11
['e', 'b', 'k'] 11
['e', 'c', 'k'] 11
['e', 'a', 'b', 'd', 'k'] 12
['e', 'a', 'c', 'd', 'k'] 12
['e', 'b', 'd', 'k'] 12
['e', 'c', 'd', 'k'] 12
['e', 'a', 'b', 'c', 'k'] 13
['e', 'b', 'c', 'k'] 13
['e', 'a', 'b', 'c', 'd', 'k'] 14
['e', 'b', 'c', 'd', 'k'] 14
['e', 'a', 'c', 'b', 'k'] 15
['e', 'a', 'd', 'c', 'k'] 15
['e', 'c', 'b', 'k'] 15
['e', 'd', 'c', 'k'] 15
['e', 'a', 'c', 'b', 'd', 'k'] 16
['e', 'c', 'b', 'd', 'k'] 16
['e', 'd', 'a', 'k'] 16
['e', 'a', 'd', 'b', 'k'] 17
['e', 'b', 'a', 'd', 'k'] 17
['e', 'b', 'a', 'k'] 17
['e', 'd', 'b', 'k'] 17
['e', 'c', 'a', 'd', 'k'] 18
['e', 'c', 'a', 'k'] 18
['e', 'a', 'b', 'd', 'c', 'k'] 19
['e', 'a', 'd', 'b', 'c', 'k'] 19
['e', 'a', 'd', 'c', 'b', 'k'] 19
['e', 'b', 'd', 'c', 'k'] 19
['e', 'd', 'a', 'b', 'k'] 19
['e', 'd', 'a', 'c', 'k'] 19
['e', 'd', 'b', 'c', 'k'] 19
['e', 'd', 'c', 'b', 'k'] 19
['e', 'b', 'a', 'c', 'k'] 20
['e', 'b', 'c', 'a', 'd', 'k'] 20
['e', 'b', 'c', 'a', 'k'] 20
['e', 'b', 'd', 'a', 'k'] 20
['e', 'c', 'd', 'a', 'k'] 20
['e', 'a', 'c', 'd', 'b', 'k'] 21
['e', 'b', 'a', 'c', 'd', 'k'] 21
['e', 'c', 'a', 'b', 'k'] 21
['e', 'c', 'b', 'a', 'd', 'k'] 21
['e', 'c', 'b', 'a', 'k'] 21
['e', 'c', 'd', 'b', 'k'] 21
['e', 'd', 'a', 'b', 'c', 'k'] 21
['e', 'b', 'c', 'd', 'a', 'k'] 22
['e', 'c', 'a', 'b', 'd', 'k'] 22
['e', 'd', 'c', 'a', 'k'] 22
['e', 'b', 'd', 'a', 'c', 'k'] 23
['e', 'c', 'd', 'a', 'b', 'k'] 23
['e', 'd', 'a', 'c', 'b', 'k'] 23
['e', 'd', 'b', 'a', 'k'] 23
['e', 'b', 'a', 'd', 'c', 'k'] 24
['e', 'c', 'b', 'd', 'a', 'k'] 24
['e', 'd', 'c', 'a', 'b', 'k'] 25
['e', 'd', 'c', 'b', 'a', 'k'] 25
['e', 'b', 'd', 'c', 'a', 'k'] 26
['e', 'd', 'b', 'a', 'c', 'k'] 26
['e', 'd', 'b', 'c', 'a', 'k'] 26
['e', 'c', 'a', 'd', 'b', 'k'] 27
['e', 'c', 'd', 'b', 'a', 'k'] 27

调用find_all_paths生成器的另一种方法是

valid_paths = sorted((pathlen, path)
    for pathlen, path in find_all_paths(graph1, start, end)
        if exists_in_graph(path, required)
)
for pathlen, path in valid_paths:
    print(path, pathlen)

这样,我们可以在对不需要的路径进行排序之前对其进行过滤。 如果你只是想在最短的路径可以取代呼叫sortedmin

pathlen, path = min((pathlen, path)
    for pathlen, path in find_all_paths(graph1, start, end)
        if exists_in_graph(path, required)
)
print(path, pathlen)

产量

['e', 'a', 'd', 'k'] 8

我对您的代码进行了其他一些小的更改。

如果用户在进入没事'via'提示,然后required设置为包含空字符串列表,并会搞乱你的exists_in_graph测试,所以如果出现这种情况,我们设定required的空单。

在您的find_all_paths版本中,您为path提供了空列表的默认值。 如果您想多次调用find_all_paths那将使事情变得混乱,因为默认args是在创建函数find_all_paths不是在调用函数时评估的。 因此,如果您在不提供path arg的情况下再次调用find_all_paths ,它将继续使用其最初使用的默认path列表,而不会使用新的空列表。 解决此问题的常用方法是使用默认值None ,就像我在代码中所做的那样。 有关此重要主题的更多信息,请参见“最小惊讶”和可变默认参数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM