发现单源,多终端(可能是循环)定向图中的所有路径

时间:2013-05-17 22:25:34

标签: python language-agnostic graph-traversal

我有一个图G = (V,E),其中

  • V{0, 1, 2, 3, …}
  • 的子集
  • EVxV
  • 的子集
  • G
  • 中没有未连接的组件
  • 图表可能包含周期
  • v中有一个已知的节点V,它是来源;即u中没有V(u,v)是边缘
  • v中至少有一个接收器/终端节点V;即u中没有V(v,u)是边缘。终端节点的身份是未知的 - 它们必须通过遍历来发现

我需要做的是计算一组路径P,以便从源节点到任何终端节点的每条可能路径都在P。现在,如果图表包含周期,则可以通过此定义P becomes an infinite set. This is not what I need. Rather, what I need is for P to contain a path that doesn't explore the loop and at least one path that does explore the loop.
I say "at least one path that does explore the loop", as the loop may contain branches internally, in which case, all of those branches will need to be explored as well. Thus, if the loop contains two internal branches, each with a branching factor of 2, then I need a total of four paths in
P`来探索循环。

例如,算法运行在下图中:

         +-------+
         |       |
         v       |
1->2->3->4->5->6 |
         |  |  | |
         v  |  v |
         9  +->7-+
               |
               v
               8

可以表示为:

1:{2}
2:{3}
3:{4}
4:{5,9}
5:{6,7}
6:{7}
7:{4,8}
8:{}
9:{}

应该产生一组路径:

1,2,3,4,9
1,2,3,4,5,6,7,8
1,2,3,4,5,6,7,4,9
1,2,3,4,5,7,8
1,2,3,4,5,7,4,9
1,2,3,4,5,7,4,5,6,7,8
1,2,3,4,5,7,4,5,7,8

到目前为止,我有以下算法(在python中),它适用于一些简单的情况:

def extractPaths(G, s=None, explored=None, path=None):
    _V,E = G
    if s is None: s = 0
    if explored is None: explored = set()
    if path is None: path = [s]
    explored.add(s)

    if not len(set(E[s]) - explored):
        print path
    for v in set(E[s]) - explored:
        if len(E[v]) > 1:
            path.append(v)
            for vv in set(E[v]) - explored:
                extractPaths(G, vv, explored-set(n for n in path if len(E[n])>1), path+[vv])
        else:
            extractPaths(G, v, explored, path+[v])

但在更复杂的情况下它会失败。

我很感激任何帮助,因为这是一个验证我为硕士论文开发的算法的工具。
提前谢谢

1 个答案:

答案 0 :(得分:1)

我已经考虑了几个小时了,并提出了这个算法。它并没有给你所要求的结果,但它是相似的(可能是等价的)。

观察:如果我们尝试转到之前看到的节点,则最近一次访问,直到当前节点,可以被视为循环。如果我们看到那个循环,我们就不能去那个节点了。

def extractPaths(current_node,path,loops_seen):
    path.append(current_node)
    # if node has outgoing edges
    if nodes[current_node]!=None:
        for thatnode in nodes[current_node]:
            valid=True
            # if the node we are going to has been
            # visited before, we are completeing
            # a loop.
            if thatnode-1 in path:
                i=len(path)-1
                # find the last time we visited
                # that node
                while path[i]!=thatnode-1:
                    i-=1
                # the last time, to this time is
                # a single loop.
                new_loop=path[i:len(path)]
                # if we haven't seen this loop go to
                # the node and node we have seen this
                # loop. else don't go to the node.
                if new_loop in loops_seen:
                    valid=False
                else:
                    loops_seen.append(new_loop)
            if valid:
                extractPaths(thatnode-1,path,loops_seen)
    # this is the end of the path
    else:
        newpath=list()
        # increment all the values for printing
        for i in path:
            newpath.append(i+1)
        found_paths.append(newpath)
    # backtrack
    path.pop()

# graph defined by lists of outgoing edges
nodes=[[2],[3],[4],[5,9],[6,7],[7],[4,8],None,None]

found_paths=list()
extractPaths(0,list(),list())
for i in found_paths:
    print(i)