【问题标题】:All Valid Possible Combinations所有有效的可能组合
【发布时间】:2019-09-02 08:54:01
【问题描述】:

我有这张有 5 个巴士站的路线图:

a --_       _--b
     \--c--/
d ---/     \---e

我需要获取所有可能的有效路径。有效路径是两个巴士站之间的路径,而不会跳过其间的任何巴士站。

例如,如果我们用二进制列表表示公交车站

            a b c d e
Stations = [1,1,1,1,1]

以下路径有效:

P1 = [1,0,1,0,1] # a <-> c <-> e
P2 = [0,0,1,1,0] # c <-> b 
P3 = [0,0,0,0,1] # e

这些都是无效的:

P4 = [1,1,0,0,0]
P5 = [0,1,0,1,0]

我创建了一个有效连接矩阵:

  a b c d e
a 1   1
b   1 1
c 1 1 1 1 1
d     1 1
e     1   1

我创造了所有可能的组合

c = list(itertools.product([0, 1], repeat=len(stations))

并将每个路径乘以上述矩阵,但我没有得到任何有意义的东西。有谁知道获得所有有效路径的方法?我们的地图上可能有任意数量的巴士站。

【问题讨论】:

  • 您可以查看类似于查找汉密尔顿路径的算法。这篇文章应该有帮助:hackerearth.com/practice/algorithms/graphs/hamiltonian-path/…
  • 一个令人困惑的路径“二进制列表”表示示例:[1, 1, 1, 0, 0]。看起来 a 转到 b 转到 c,但这是无效的。但这可能意味着a 转到c 转到b,这是一个有效路径。
  • 我的意思是,您当然可以生成您指定的表示形式的所有路径,但正如@RoryDaulton 所说,这似乎不是一个有用的表示形式......
  • @RoryDaulton 我不知道如何回答“你知道多少图论?你了解广度优先搜索、深度优先搜索等吗?”路径 [1,1,1,0,0] 将是有效路径,因为您可以为巴士站 a、d 和 c 提供巴士路线。 [1,1,0,0,0] 是无效的,因为你不能在不通过 c 的情况下从 a 到 d 或 d 到 a。如果你还是不明白,我可以给你更多例子。

标签: python algorithm


【解决方案1】:

这个答案包含一个简单的 DFS 解决方案(对于大图不一定非常高效)。

设置图表:

graph = {
    'a': {'c'},
    'b': {'c'},
    'c': {'a', 'b', 'd', 'e'},
    'd': {'c'},
    'e': {'c'},
}

给定一个节点和访问节点列表,枚举所有可能的子路径:

def list_paths(node, excluded_nodes):
    excluded_nodes = set(excluded_nodes)
    excluded_nodes.add(node)
    yield [node]
    yield from [[node] + p
        for x in graph[node] - excluded_nodes
        for p in list_paths(x, excluded_nodes)]

对所有起始节点执行此操作:

def list_all_paths():
    for k in graph:
        yield from list_paths(k, set())

最后,运行这个我们得到:

>>> from pprint import pprint
>>> pprint(list(list_all_paths()))
[['a'],
 ['a', 'c'],
 ['a', 'c', 'b'],
 ['a', 'c', 'd'],
 ['a', 'c', 'e'],
 ['b'],
 ['b', 'c'],
 ['b', 'c', 'a'],
 ['b', 'c', 'd'],
 ['b', 'c', 'e'],
 ['c'],
 ['c', 'a'],
 ['c', 'd'],
 ['c', 'b'],
 ['c', 'e'],
 ['d'],
 ['d', 'c'],
 ['d', 'c', 'a'],
 ['d', 'c', 'b'],
 ['d', 'c', 'e'],
 ['e'],
 ['e', 'c'],
 ['e', 'c', 'a'],
 ['e', 'c', 'd'],
 ['e', 'c', 'b']]

当然,您可以非常简单地将这些嵌入到您自己的向量中:

def list_all_vectors():
    embedding = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}
    zero = [0 for x in range(len(embedding))]
    for path in list_all_paths():
        v = list(zero)
        for x in path:
            v[embedding[x]] = 1
        yield v

pprint(list(list_all_vectors()))

您会注意到,对于较大的图形,这很容易一遍又一遍地重新计算相同的子路径。对此的快速修复可能是某种记忆,但通常可能有更好的算法。 (尝试谷歌搜索“枚举所有哈密顿路径”。)

【讨论】:

    【解决方案2】:

    在我看来,这就像一个树算法。

    从任何起点,列出所有可以直接到达的巴士站。

    从A开始,得到A-D和A-C

    从每一个重复,除非不要去我们已经去过的站点。 (如果已经在我们去过的站点列表中,请不要添加字母)

    AD - C(从 A-D,然后添加 C)

    AC-D、AC-B、AC-E

    再重复一遍

    ADC-B、ADC-E

    ACD -(分支结束)

    ACB-E(分支结束)

    对剩余的起点重复该过程, 可能的路径总数,是发现的所有路径的并集。

    与其将其视为数组问题,不如将其视为构建一组字符串。 如果您创建能够很好地代表问题的数据结构,那么该算法通常更容易理解和实现。

    您需要首先输入路线图,以提供所有邻居站点的方式

    A: C,D

    B: C,E

    C:A、B、D、E

    D: A,C

    E: B,C

    希望这会有所帮助。这就是我现在所有的时间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2012-03-27
      • 2019-05-20
      相关资源
      最近更新 更多