简体   繁体   English

在Erlang中查找有向循环图中一个顶点的所有可能路径

[英]Find all possible paths from one vertex in a directed cyclic graph in Erlang

I would like to implement a function which finds all possible paths to all possible vertices from a source vertex V in a directed cyclic graph G. 我想实现一个函数,该函数在有向循环图G中找到来自源顶点V的所有可能顶点的所有可能路径。

The performance doesn't matter now, I just would like to understand the algorithm. 性能现在没关系,我只是想了解算法。 I have read the definition of the Depth-first search algorithm, but I don't have full comprehension of what to do. 我已经阅读了深度优先搜索算法的定义,但我并不完全理解该怎么做。

I don't have any completed piece of code to provide here, because I am not sure how to: 我没有在这里提供任何完整的代码,因为我不知道如何:

  • store the results (along with A->B->C-> we should also store A->B and A->B->C); 存储结果(连同A-> B-> C->我们还应该存储A-> B和A-> B-> C);
  • represent the graph (digraph? list of tuples?); 代表图(有向图?元组列表?);
  • how many recursions to use (work with each adjacent vertex?). 要使用多少递归(处理每个相邻的顶点?)。

How can I find all possible paths form one given source vertex in a directed cyclic graph in Erlang? 如何在Erlang中的有向循环图中找到形成一个给定源顶点的所有可能路径?

UPD: Based on the answers so far I have to redefine the graph definition: it is a non-acyclic graph. UPD:基于到目前为止的答案,我必须重新定义图形定义:它是一个非非循环图形。 I know that if my recursive function hits a cycle it is an indefinite loop. 我知道如果我的递归函数遇到一个循环,它就是一个无限循环。 To avoid that, I can just check if a current vertex is in the list of the resulting path - if yes, I stop traversing and return the path. 为了避免这种情况,我可以检查当前顶点是否在结果路径的列表中 - 如果是,我停止遍历并返回路径。


UPD2: Thanks for thought provoking comments! UPD2:感谢发人深省的评论! Yes, I need to find all simple paths that do not have loops from one source vertex to all the others. 是的,我需要找到所有没有从一个源顶点到所有其他源的循环的简单路径。

In a graph like this: 在这样的图表中:

非非循环图

with the source vertex A the algorithm should find the following paths: 使用源顶点A算法应找到以下路径:

  • A,B A,B
  • A,B,C A,B,C
  • A,B,C,D A B C D
  • A,D 广告
  • A,D,C A,d,C
  • A,D,C,B A,d,C,B

The following code does the job, but it is unusable with graphs that have more that 20 vertices (I guess it is something wrong with recursion - takes too much memory, never ends): 下面的代码完成了这项工作,但是对于具有更多20个顶点的图形它是不可用的(我猜它是递归错误的东西 - 占用太多内存,永远不会结束):

dfs(Graph,Source) ->
    ?DBG("Started to traverse graph~n", []),
            Neighbours = digraph:out_neighbours(Graph,Source),
    ?DBG("Entering recursion for source vertex ~w~n", [Source]),
            dfs(Neighbours,[Source],[],Graph,Source),
ok.


dfs([],Paths,Result,_Graph,Source) ->
    ?DBG("There are no more neighbours left for vertex ~w~n", [Source]),
    Result;

dfs([Neighbour|Other_neighbours],Paths,Result,Graph,Source) ->
    ?DBG("///The neighbour to check is ~w, other neighbours are: ~w~n",[Neighbour,Other_neighbours]),
    ?DBG("***Current result: ~w~n",[Result]),
    New_result = relax_neighbours(Neighbour,Paths,Result,Graph,Source),

        dfs(Other_neighbours,Paths,New_result,Graph,Source).


relax_neighbours(Neighbour,Paths,Result,Graph,Source) ->
     case lists:member(Neighbour,Paths) of 
        false ->
            ?DBG("Found an unvisited neighbour ~w, path is: ~w~n",[Neighbour,Paths]),
            Neighbours = digraph:out_neighbours(Graph,Neighbour),
            ?DBG("The neighbours of the unvisited vertex ~w are ~w, path is:
                ~w~n",[Neighbour,Neighbours,[Neighbour|Paths]]),
                dfs(Neighbours,[Neighbour|Paths],Result,Graph,Source);
            true ->
                [Paths|Result]

        end.

UPD3: UPD3:

The problem is that the regular depth-first search algorithm will go one of the to paths first: (A,B,C,D) or (A,D,C,B) and will never go the second path. 问题是常规的深度优先搜索算法将首先进入路径之一:(A,B,C,D)或(A,D,C,B)并且永远不会进入第二条路径。

In either case it will be the only path - for example, when the regular DFS backtracks from (A,B,C,D) it goes back up to A and checks if D (the second neighbour of A) is visited. 在任何一种情况下,它都是唯一的路径 - 例如,当常规DFS从(A,B,C,D)回溯时,它返回到A并检查是否访问了D(A的第二个邻居)。 And since the regular DFS maintains a global state for each vertex, D would have 'visited' state. 由于常规DFS为每个顶点维护一个全局状态,因此D将具有“已访问”状态。

So, we have to introduce a recursion-dependent state - if we backtrack from (A,B,C,D) up to A, we should have (A,B,C,D) in the list of the results and we should have D marked as unvisited as at the very beginning of the algorithm. 所以,我们必须引入一个依赖于递归的状态 - 如果我们从(A,B,C,D)回溯到A,我们应该在结果列表中有(A,B,C,D),我们应该在算法的最开始,将D标记为未访问。

I have tried to optimize the solution to tail-recursive one, but still the running time of the algorithm is unfeasible - it takes about 4 seconds to traverse a tiny graph of 16 vertices with 3 edges per vertex: 我试图将解决方案优化为尾递归算法,但算法的运行时间仍然不可行 - 遍历16个顶点的小图表需要大约4秒钟,每个顶点有3个边缘:

dfs(Graph,Source) ->
    ?DBG("Started to traverse graph~n", []),
            Neighbours = digraph:out_neighbours(Graph,Source),
    ?DBG("Entering recursion for source vertex ~w~n", [Source]),
    Result = ets:new(resulting_paths, [bag]),
Root = Source,
            dfs(Neighbours,[Source],Result,Graph,Source,[],Root).


dfs([],Paths,Result,_Graph,Source,_,_) ->
    ?DBG("There are no more neighbours left for vertex ~w, paths are ~w, result is ~w~n", [Source,Paths,Result]),
    Result;

dfs([Neighbour|Other_neighbours],Paths,Result,Graph,Source,Recursion_list,Root) ->
    ?DBG("~w *Current source is ~w~n",[Recursion_list,Source]),
    ?DBG("~w Checking neighbour _~w_ of _~w_, other neighbours are: ~w~n",[Recursion_list,Neighbour,Source,Other_neighbours]),



?    DBG("~w Ready to check for visited: ~w~n",[Recursion_list,Neighbour]),

 case lists:member(Neighbour,Paths) of 
        false ->
            ?DBG("~w Found an unvisited neighbour ~w, path is: ~w~n",[Recursion_list,Neighbour,Paths]),
New_paths = [Neighbour|Paths],
?DBG("~w Added neighbour to paths: ~w~n",[Recursion_list,New_paths]),
ets:insert(Result,{Root,Paths}),

            Neighbours = digraph:out_neighbours(Graph,Neighbour),
            ?DBG("~w The neighbours of the unvisited vertex ~w are ~w, path is: ~w, recursion:~n",[Recursion_list,Neighbour,Neighbours,[Neighbour|Paths]]),
                dfs(Neighbours,New_paths,Result,Graph,Neighbour,[[[]]|Recursion_list],Root);
            true -> 
            ?DBG("~w The neighbour ~w is: already visited, paths: ~w, backtracking to other neighbours:~n",[Recursion_list,Neighbour,Paths]),
ets:insert(Result,{Root,Paths})

end,

        dfs(Other_neighbours,Paths,Result,Graph,Source,Recursion_list,Root).

Any ideas to run this in acceptable time? 有什么想法在可接受的时间运行吗?

I don't understand question. 我不明白问题。 If I have graph G = (V, E) = ({A,B}, {(A,B),(B,A)}), there is infinite paths from A to B {[A,B], [A,B,A,B], [A,B,A,B,A,B], ...}. 如果我有图G =(V,E)=({A,B},{(A,B),(B,A)}),从A到B有无限路径{[A,B],[ A,B,A,B],[A,B,A,B,A,B],......}。 How I can find all possible paths to any vertex in cyclic graph? 如何找到循环图中任何顶点的所有可能路径?

Edit: 编辑:

Did you even tried compute or guess growing of possible paths for some graphs? 您是否尝试过计算或猜测某些图形的可能路径增长? If you have fully connected graph you will get 如果你有完全连接的图表,你会得到

  • 2 - 1 2 - 1
  • 3 - 4 3 - 4
  • 4 - 15 4 - 15
  • 5 - 64 5 - 64
  • 6 - 325 6 - 325
  • 7 - 1956 7 - 1956年
  • 8 - 13699 8 - 13699
  • 9 - 109600 9 - 109600
  • 10 - 986409 10 - 986409
  • 11 - 9864100 11 - 9864100
  • 12 - 108505111 12 - 108505111
  • 13 - 1302061344 13 - 1302061344
  • 14 - 16926797485 14 - 16926797485
  • 15 - 236975164804 15 - 236975164804
  • 16 - 3554627472075 16 - 3554627472075
  • 17 - 56874039553216 17 - 56874039553216
  • 18 - 966858672404689 18 - 966858672404689
  • 19 - 17403456103284420 19 - 17403456103284420
  • 20 - 330665665962403999 20 - 330665665962403999

Are you sure you would like find all paths for all nodes? 您确定要查找所有节点的所有路径吗? It means if you compute one milion paths in one second it would take 10750 years to compute all paths to all nodes in fully connected graph with 20 nodes. 这意味着如果您在一秒钟内计算一个百万路径,则需要10750年来计算到具有20个节点的完全连接图中所有节点的所有路径。 It is upper bound for your task so I think you don't would like do it. 它是你的任务的上限,所以我认为你不想这样做。 I think you want something else. 我想你想要别的东西。

Edit: Okay I understand now, you want to find all simple paths from a vertex in a directed graph. 编辑:好的,我现在明白了,你想要从有向图中的顶点找到所有简单路径。 So a depth-first search with backtracking would be suitable, as you have realised. 因此,正如您已经意识到的那样,使用回溯的深度优先搜索将是合适的。 The general idea is to go to a neighbour, then go to another one (not one which you've visited), and keep going until you hit a dead end. 一般的想法是去邻居,然后去另一个(不是你去过的那个),并继续前进,直到你走到尽头。 Then backtrack to the last vertex you were at and pick a different neighbour, etc. You need to get the fiddly bits right, but it shouldn't be too hard. 然后回溯到你所在的最后一个顶点并选择一个不同的邻居等。你需要得到正确的位,但它不应该太难。 Eg at every step you need to label the vertices 'explored' or 'unexplored' depending on whether you've already visited them before. 例如,在每个步骤中,您需要根据您之前是否已经访问它们来标记顶点的“探索”或“未探测”。 The performance shouldn't be an issue, a properly implemented algorithm should take maybe O(n^2) time. 性能应该不是问题,正确实现的算法应该花费O(n ^ 2)时间。 So I don't know what you are doing wrong, perhaps you are visiting too many neighbours? 所以我不知道你做错了什么,也许你正在拜访太多的邻居? Eg maybe you are revisiting neighbours that you've already visited, and going round in loops or something. 例如,也许你正在重新访问你已经访问过的邻居,并绕圈或其他东西。

I haven't really read your program, but the Wiki page on Depth-first Search has a short, simple pseudocode program which you can try to copy in your language. 我还没有真正阅读过您的程序,但深度优先搜索的Wiki页面有一个简短的伪代码程序,您可以尝试使用您的语言进行复制。 Store the graphs as Adjacency Lists to make it easier. 将图形存储为邻接列表以使其更容易。

Edit: Yes, sorry, you are right, the standard DFS search won't work as it stands, you need to adjust it slightly so that does revisit vertices it has visited before. 编辑:是的,对不起,你是对的,标准的DFS搜索将无法正常工作,你需要稍微调整它,以便重新访问它之前访问过的顶点。 So you are allowed to visit any vertices except the ones you have already stored in your current path. 因此,您可以访问除已存储在当前路径中的顶点之外的任何顶点。 This of course means my running time was completely wrong, the complexity of your algorithm will be through the roof. 这当然意味着我的运行时间完全错误,算法的复杂性将通过屋顶。 If the average complexity of your graph is d+1, then there will be approximately d*d*d*...*d = d^n possible paths. 如果图的平均复杂度为d + 1,那么将会有大约d * d * d * ... * d = d ^ n个可能的路径。 So even if every vertex has only 3 neighbours, there's still quite a few paths when you get above 20 vertices. 因此,即使每个顶点只有3个邻居,当你获得20个以上的顶点时,仍然会有相当多的路径。 There's no way around that really, because if you want your program to output all possible paths then indeed you will have to output all d^n of them. 真的没办法,因为如果你希望你的程序输出所有可能的路径,那么你确实必须输出所有d ^ n。

I'm interested to know whether you need this for a specific task, or are just trying to program this out of interest. 我很想知道您是否需要针对特定​​任务执行此操作,或者只是想尝试对此进行编程。 If the latter, you will just have to be happy with small, sparsely connected graphs. 如果是后者,您只需要对小的,稀疏连接的图表感到满意。

Not an improved algorithmic solution by any means, but you can often improve performance by spawning multiple worker threads, potentially here one for each first level node and then aggregating the results. 无论如何都不是改进的算法解决方案,但是您通常可以通过生成多个工作线程来提高性能,这可能是每个第一级节点一个,然后聚合结果。 This can often improve naive brute force algorithms relatively easily. 这通常可以相对容易地改善幼稚蛮力算法。

You can see an example here: Some Erlang Matrix Functions , in the maximise_assignment function (comments starting on line 191 as of today). 你可以在这里看到一个例子:maximise_assignment函数中的一些Erlang矩阵函数(从今天开始的第191行开始的注释)。 Again, the underlying algorithm there is fairly naive and brute force, but the parallelisation speeds it up quite well for many forms of matrices. 同样,基础算法存在相当天真和蛮力,但并行化可以很好地加速许多形式的矩阵。

I have used a similar approach in the past to find the number of Hamiltonian Paths in a graph. 我过去使用过类似的方法来查找图中哈密顿路径的数量。

暂无
暂无

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

相关问题 在加权循环有向图中找到从源到目的地的所有路径 - Find all paths from source to destination in a weighted cyclic directed graph 在有向循环图中查找所有路径 - Find All paths in a Directed Cyclic Graph 在给定起始顶点和深度限制的情况下查找循环有向图中的所有可能路径 - Finding all possible paths in a cyclic directed graph given a starting vertex and a depth limitation 给定源顶点,在有向图中找到带有循环的所有路径 - Find all paths with cycles in directed graph, given the source vertex 完全连接的有向图中,所有可能的非循环简单路径的数量是多少? - What is the number of all possible non-cyclic simple paths in a fully-connected directed graph? 在加权定向循环图中寻找从A到B的不同路径的算法 - Algorithm for finding distinct paths from A to B in weighted, directed, cyclic graph 如何在有向图中找到所有欧拉路径 - How to find ALL Eulerian paths in directed graph 如何找到有向图中2个特定顶点之间的所有可能路径中存在的顶点? - How to find vertices exist in all possible route between 2 specific vertex in a directed graph? 在未知大小的加权有向图上,一个人如何遍历两个顶点之间从最短到最长的所有可能的非循环路径? - On a weighted directed graph of unknown size, how can one iterate over all possible acyclic paths between two vertices from shortest to longest? 找到有向图的顶点在时间O(| E | + | V |)中可到达的所有顶点 - Find all vertices reachable from a vertex of a directed graph in time O(|E| + |V|)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM