我正在尝试开发一种算法,用于识别图形中两个节点之间的所有可能路径,如下例所示:
事实上,我只需知道哪些节点出现在所有现有路径中。 网上的
只有关于DFS,A *或dijkstra的引用,但我认为它们在这种情况下不起作用。
有谁知道如何解决它?
答案 0 :(得分:4)
您可以使用DFS找到所有路径,例如| Vlad描述。要找到每个路径中出现的节点,您可以只维护一个布尔数组,说明到目前为止每个节点是否都出现在每个路径中。当DFS找到路径时,请遍历路径中的每个顶点而不是,并将相应的数组值设置为false。完成后,只有值为true的顶点才会出现在每个路径中。
伪代码:
int source;
int sink;
int nVerts;
bool inAllPaths[nVerts]; // init to all true
bool visited[nVerts]; // init to all false
stack<int> path; // init empty
bool dfs(int u)
if (visited[u])
return;
if (u == sink)
for i = 0 to nVerts-1
if !stack.contains(i)
inAllPaths[i] = false;
return true;
else
visited[u] = true;
stack.push(u);
foreach edge (u, v)
dfs(v);
stack.pop();
visited[u] = false;
return false;
main()
dfs(source);
// inAllPaths contains true at vertices that exist in all paths
// from source to sink.
但是,这种算法效率不高。例如,在n个顶点的完整图形中(所有顶点都与所有其他顶点具有边缘),路径的数量将为n! (n阶乘)。
更好的算法是分别检查每个顶点的每个路径中是否存在。对于每个顶点,尝试找到从源到接收器的路径,而不必去往该顶点。如果找不到,那是因为顶点出现在每个路径中。
伪代码:
// Using the same initialisation as above, but with a slight modification
// to dfs: change the foreach loop to
foreach edge (u, v)
if (dfs(v))
return true; // exit as soon as we find a path
main()
for i = 0 to nVerts-1
set all visited to false;
if (inAllPaths[i])
visited[i] = true;
if (dfs(source))
inAllPaths[i] = false;
visited[i] = false;
不幸的是,在搜索路径时,这仍然是指数最坏的情况。您可以通过将搜索更改为广度优先搜索来解决此问题。如果我没弄错的话,这应该会给你O(VE)表现。
答案 1 :(得分:1)
从起始节点运行DFS,并保留自己的堆栈,告诉您在任何给定时间看到的节点。注意循环:当你看到一个节点两次时,你有一个循环,你必须中止你当前的路径。注意不要访问节点的父节点,以避免长度为1的循环(向DFS函数添加parent
参数,这将有所帮助)。
然后,当您到达目标节点时,输出堆栈的内容。
DFS完成后,您将拥有所有路径。
答案 2 :(得分:1)
对于这个问题,我首先会在你的一个目标节点u上得到一个由DFS组成的树。然后,为根据第二个目标节点v的子树中的所有节点着色,比如蓝色。
For each node k in subtree s,
if k has an edge to a non-blue node x
then k is true and x is true.
另外,将v标记为true。最后,我会使用递归函数到叶子。像
这样的东西function(node n){
if(n = null)
return false
if(function(n.left) or function(n.right) or n.val){
n.val = true
return true
}
else
return false
}
标记为true的所有节点都是从u到v的路径中的节点。运行时最多(Vertices + Edges),因为DFS =(V + E)for循环最多(V)最多递归(V)
答案 3 :(得分:1)
我知道已经有一段时间了,但我来到这里寻找一些算法来查找SQL或Java中的所有路径(不仅是最短路径)而且我发现了这三个(我只是发布它们以保持概念组织):< / p>
爪哇
http://introcs.cs.princeton.edu/java/45graph/AllPaths.java.html(依赖项:图形,ST,Set,In,位于http://introcs.cs.princeton.edu/java/45graph/)
SQL(PostgreSQL)。
检查WITH RECURSIVE transitive_closure(a, b, distance, path_string) AS
http://techportal.inviqa.com/2009/09/07/graphs-in-the-database-sql-meets-social-networks/
PL / SQL(Oracle)
https://forums.oracle.com/forums/thread.jspa?threadID=2415733
select pth as "Path", distance as "Distance"
from (
select connect_by_root(n1) || sys_connect_by_path(n2,'>') pth ,n2, level as distance
from -- Edge List Table
(select 'A' n1,'B' n2 from dual
union all select 'A','C' from dual
union all select 'B','C' from dual
union all select 'B','D' from dual
union all select 'D','G' from dual
union all select 'C','G' from dual
union all select 'D','I' from dual
union all select 'C','E' from dual
union all select 'E','F' from dual
union all select 'F','G' from dual
union all select 'F','H' from dual
) links
start with n1='A'
connect by nocycle prior n2=n1)
where n2 = 'G';
结果:
Distance Path
3 A>B>C>G
5 A>B>C>E>F>G
3 A>B>D>G
2 A>C>G
4 A>C>E>F>G
如果您在评论中添加start with n1...
行和where n2...
行,则查询将返回所有图表中的所有路径。
答案 4 :(得分:0)
一个顶点位于从A到B的路径上,如果它可以从A到达,并且B可以从它到达。
所以:从A开始进行洪水填充。标记所有这些顶点。 从B开始进行洪水填充,然后反向跟随边缘。您遇到的所有标记顶点都是解决方案的一部分。